diff options
author | Andrew F. Davis | 2018-07-24 08:20:35 -0500 |
---|---|---|
committer | Alistair Strachan | 2018-08-31 13:00:04 -0500 |
commit | 8eaa2bfcd5a0abbd52051f14de0c0e200e98175b (patch) | |
tree | 624db8896f88f8680bb2e8a1e100497230716b65 | |
parent | 86a022aa92b8f174df250113f4717737b9edfd25 (diff) | |
download | hardware-ti-am57x-8eaa2bfcd5a0abbd52051f14de0c0e200e98175b.tar.gz hardware-ti-am57x-8eaa2bfcd5a0abbd52051f14de0c0e200e98175b.tar.xz hardware-ti-am57x-8eaa2bfcd5a0abbd52051f14de0c0e200e98175b.zip |
libhwcomposer: Add initial support
Add basic HW Composer support that allows boot to UI. More
functionality will be added incrementally.
Test: Boot to UI with BeagleBoard X15
Change-Id: I9803cc892dfe85b8b9929229ba3b86f2bd9d36bc
Signed-off-by: Andrew F. Davis <afd@ti.com>
-rw-r--r-- | libhwcomposer/Android.bp | 44 | ||||
-rw-r--r-- | libhwcomposer/NOTICE | 203 | ||||
-rw-r--r-- | libhwcomposer/display.cpp | 273 | ||||
-rw-r--r-- | libhwcomposer/display.h | 126 | ||||
-rw-r--r-- | libhwcomposer/drmfb.cpp | 100 | ||||
-rw-r--r-- | libhwcomposer/drmfb.h | 35 | ||||
-rw-r--r-- | libhwcomposer/format.cpp | 152 | ||||
-rw-r--r-- | libhwcomposer/format.h | 63 | ||||
-rw-r--r-- | libhwcomposer/hal_public.h | 245 | ||||
-rw-r--r-- | libhwcomposer/hwc.cpp | 724 | ||||
-rw-r--r-- | libhwcomposer/hwc_dev.h | 57 |
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 @@ | |||
1 | // Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ | ||
2 | // | ||
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | // you may not use this file except in compliance with the License. | ||
5 | // You may obtain a copy of the License at | ||
6 | // | ||
7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | // | ||
9 | // Unless required by applicable law or agreed to in writing, software | ||
10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | // See the License for the specific language governing permissions and | ||
13 | // limitations under the License. | ||
14 | |||
15 | cc_library_shared { | ||
16 | name: "hwcomposer.am57x", | ||
17 | |||
18 | vendor: true, | ||
19 | relative_install_path: "hw", | ||
20 | |||
21 | srcs: [ | ||
22 | "display.cpp", | ||
23 | "drmfb.cpp", | ||
24 | "format.cpp", | ||
25 | "hwc.cpp", | ||
26 | ], | ||
27 | |||
28 | cflags: [ | ||
29 | "-DLOG_TAG=\"ti_hwc\"", | ||
30 | "-Wno-unused-parameter", | ||
31 | "-Wno-missing-field-initializers", | ||
32 | "-fexceptions", | ||
33 | ], | ||
34 | |||
35 | shared_libs: [ | ||
36 | "liblog", | ||
37 | "libcutils", | ||
38 | "libutils", | ||
39 | "libhardware", | ||
40 | "libhardware_legacy", | ||
41 | "libdrm", | ||
42 | "libkmsxx", | ||
43 | ], | ||
44 | } | ||
diff --git a/libhwcomposer/NOTICE b/libhwcomposer/NOTICE new file mode 100644 index 0000000..6b0b127 --- /dev/null +++ b/libhwcomposer/NOTICE | |||
@@ -0,0 +1,203 @@ | |||
1 | |||
2 | Apache License | ||
3 | Version 2.0, January 2004 | ||
4 | http://www.apache.org/licenses/ | ||
5 | |||
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||
7 | |||
8 | 1. Definitions. | ||
9 | |||
10 | "License" shall mean the terms and conditions for use, reproduction, | ||
11 | and distribution as defined by Sections 1 through 9 of this document. | ||
12 | |||
13 | "Licensor" shall mean the copyright owner or entity authorized by | ||
14 | the copyright owner that is granting the License. | ||
15 | |||
16 | "Legal Entity" shall mean the union of the acting entity and all | ||
17 | other entities that control, are controlled by, or are under common | ||
18 | control with that entity. For the purposes of this definition, | ||
19 | "control" means (i) the power, direct or indirect, to cause the | ||
20 | direction or management of such entity, whether by contract or | ||
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||
22 | outstanding shares, or (iii) beneficial ownership of such entity. | ||
23 | |||
24 | "You" (or "Your") shall mean an individual or Legal Entity | ||
25 | exercising permissions granted by this License. | ||
26 | |||
27 | "Source" form shall mean the preferred form for making modifications, | ||
28 | including but not limited to software source code, documentation | ||
29 | source, and configuration files. | ||
30 | |||
31 | "Object" form shall mean any form resulting from mechanical | ||
32 | transformation or translation of a Source form, including but | ||
33 | not limited to compiled object code, generated documentation, | ||
34 | and conversions to other media types. | ||
35 | |||
36 | "Work" shall mean the work of authorship, whether in Source or | ||
37 | Object form, made available under the License, as indicated by a | ||
38 | copyright notice that is included in or attached to the work | ||
39 | (an example is provided in the Appendix below). | ||
40 | |||
41 | "Derivative Works" shall mean any work, whether in Source or Object | ||
42 | form, that is based on (or derived from) the Work and for which the | ||
43 | editorial revisions, annotations, elaborations, or other modifications | ||
44 | represent, as a whole, an original work of authorship. For the purposes | ||
45 | of this License, Derivative Works shall not include works that remain | ||
46 | separable from, or merely link (or bind by name) to the interfaces of, | ||
47 | the Work and Derivative Works thereof. | ||
48 | |||
49 | "Contribution" shall mean any work of authorship, including | ||
50 | the original version of the Work and any modifications or additions | ||
51 | to that Work or Derivative Works thereof, that is intentionally | ||
52 | submitted to Licensor for inclusion in the Work by the copyright owner | ||
53 | or by an individual or Legal Entity authorized to submit on behalf of | ||
54 | the copyright owner. For the purposes of this definition, "submitted" | ||
55 | means any form of electronic, verbal, or written communication sent | ||
56 | to the Licensor or its representatives, including but not limited to | ||
57 | communication on electronic mailing lists, source code control systems, | ||
58 | and issue tracking systems that are managed by, or on behalf of, the | ||
59 | Licensor for the purpose of discussing and improving the Work, but | ||
60 | excluding communication that is conspicuously marked or otherwise | ||
61 | designated in writing by the copyright owner as "Not a Contribution." | ||
62 | |||
63 | "Contributor" shall mean Licensor and any individual or Legal Entity | ||
64 | on behalf of whom a Contribution has been received by Licensor and | ||
65 | subsequently incorporated within the Work. | ||
66 | |||
67 | 2. Grant of Copyright License. Subject to the terms and conditions of | ||
68 | this License, each Contributor hereby grants to You a perpetual, | ||
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
70 | copyright license to reproduce, prepare Derivative Works of, | ||
71 | publicly display, publicly perform, sublicense, and distribute the | ||
72 | Work and such Derivative Works in Source or Object form. | ||
73 | |||
74 | 3. Grant of Patent License. Subject to the terms and conditions of | ||
75 | this License, each Contributor hereby grants to You a perpetual, | ||
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
77 | (except as stated in this section) patent license to make, have made, | ||
78 | use, offer to sell, sell, import, and otherwise transfer the Work, | ||
79 | where such license applies only to those patent claims licensable | ||
80 | by such Contributor that are necessarily infringed by their | ||
81 | Contribution(s) alone or by combination of their Contribution(s) | ||
82 | with the Work to which such Contribution(s) was submitted. If You | ||
83 | institute patent litigation against any entity (including a | ||
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work | ||
85 | or a Contribution incorporated within the Work constitutes direct | ||
86 | or contributory patent infringement, then any patent licenses | ||
87 | granted to You under this License for that Work shall terminate | ||
88 | as of the date such litigation is filed. | ||
89 | |||
90 | 4. Redistribution. You may reproduce and distribute copies of the | ||
91 | Work or Derivative Works thereof in any medium, with or without | ||
92 | modifications, and in Source or Object form, provided that You | ||
93 | meet the following conditions: | ||
94 | |||
95 | (a) You must give any other recipients of the Work or | ||
96 | Derivative Works a copy of this License; and | ||
97 | |||
98 | (b) You must cause any modified files to carry prominent notices | ||
99 | stating that You changed the files; and | ||
100 | |||
101 | (c) You must retain, in the Source form of any Derivative Works | ||
102 | that You distribute, all copyright, patent, trademark, and | ||
103 | attribution notices from the Source form of the Work, | ||
104 | excluding those notices that do not pertain to any part of | ||
105 | the Derivative Works; and | ||
106 | |||
107 | (d) If the Work includes a "NOTICE" text file as part of its | ||
108 | distribution, then any Derivative Works that You distribute must | ||
109 | include a readable copy of the attribution notices contained | ||
110 | within such NOTICE file, excluding those notices that do not | ||
111 | pertain to any part of the Derivative Works, in at least one | ||
112 | of the following places: within a NOTICE text file distributed | ||
113 | as part of the Derivative Works; within the Source form or | ||
114 | documentation, if provided along with the Derivative Works; or, | ||
115 | within a display generated by the Derivative Works, if and | ||
116 | wherever such third-party notices normally appear. The contents | ||
117 | of the NOTICE file are for informational purposes only and | ||
118 | do not modify the License. You may add Your own attribution | ||
119 | notices within Derivative Works that You distribute, alongside | ||
120 | or as an addendum to the NOTICE text from the Work, provided | ||
121 | that such additional attribution notices cannot be construed | ||
122 | as modifying the License. | ||
123 | |||
124 | You may add Your own copyright statement to Your modifications and | ||
125 | may provide additional or different license terms and conditions | ||
126 | for use, reproduction, or distribution of Your modifications, or | ||
127 | for any such Derivative Works as a whole, provided Your use, | ||
128 | reproduction, and distribution of the Work otherwise complies with | ||
129 | the conditions stated in this License. | ||
130 | |||
131 | 5. Submission of Contributions. Unless You explicitly state otherwise, | ||
132 | any Contribution intentionally submitted for inclusion in the Work | ||
133 | by You to the Licensor shall be under the terms and conditions of | ||
134 | this License, without any additional terms or conditions. | ||
135 | Notwithstanding the above, nothing herein shall supersede or modify | ||
136 | the terms of any separate license agreement you may have executed | ||
137 | with Licensor regarding such Contributions. | ||
138 | |||
139 | 6. Trademarks. This License does not grant permission to use the trade | ||
140 | names, trademarks, service marks, or product names of the Licensor, | ||
141 | except as required for reasonable and customary use in describing the | ||
142 | origin of the Work and reproducing the content of the NOTICE file. | ||
143 | |||
144 | 7. Disclaimer of Warranty. Unless required by applicable law or | ||
145 | agreed to in writing, Licensor provides the Work (and each | ||
146 | Contributor provides its Contributions) on an "AS IS" BASIS, | ||
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||
148 | implied, including, without limitation, any warranties or conditions | ||
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||
150 | PARTICULAR PURPOSE. You are solely responsible for determining the | ||
151 | appropriateness of using or redistributing the Work and assume any | ||
152 | risks associated with Your exercise of permissions under this License. | ||
153 | |||
154 | 8. Limitation of Liability. In no event and under no legal theory, | ||
155 | whether in tort (including negligence), contract, or otherwise, | ||
156 | unless required by applicable law (such as deliberate and grossly | ||
157 | negligent acts) or agreed to in writing, shall any Contributor be | ||
158 | liable to You for damages, including any direct, indirect, special, | ||
159 | incidental, or consequential damages of any character arising as a | ||
160 | result of this License or out of the use or inability to use the | ||
161 | Work (including but not limited to damages for loss of goodwill, | ||
162 | work stoppage, computer failure or malfunction, or any and all | ||
163 | other commercial damages or losses), even if such Contributor | ||
164 | has been advised of the possibility of such damages. | ||
165 | |||
166 | 9. Accepting Warranty or Additional Liability. While redistributing | ||
167 | the Work or Derivative Works thereof, You may choose to offer, | ||
168 | and charge a fee for, acceptance of support, warranty, indemnity, | ||
169 | or other liability obligations and/or rights consistent with this | ||
170 | License. However, in accepting such obligations, You may act only | ||
171 | on Your own behalf and on Your sole responsibility, not on behalf | ||
172 | of any other Contributor, and only if You agree to indemnify, | ||
173 | defend, and hold each Contributor harmless for any liability | ||
174 | incurred by, or claims asserted against, such Contributor by reason | ||
175 | of your accepting any such warranty or additional liability. | ||
176 | |||
177 | END OF TERMS AND CONDITIONS | ||
178 | |||
179 | APPENDIX: How to apply the Apache License to your work. | ||
180 | |||
181 | To apply the Apache License to your work, attach the following | ||
182 | boilerplate notice, with the fields enclosed by brackets "[]" | ||
183 | replaced with your own identifying information. (Don't include | ||
184 | the brackets!) The text should be enclosed in the appropriate | ||
185 | comment syntax for the file format. We also recommend that a | ||
186 | file or class name and description of purpose be included on the | ||
187 | same "printed page" as the copyright notice for easier | ||
188 | identification within third-party archives. | ||
189 | |||
190 | Copyright [yyyy] [name of copyright owner] | ||
191 | |||
192 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
193 | you may not use this file except in compliance with the License. | ||
194 | You may obtain a copy of the License at | ||
195 | |||
196 | http://www.apache.org/licenses/LICENSE-2.0 | ||
197 | |||
198 | Unless required by applicable law or agreed to in writing, software | ||
199 | distributed under the License is distributed on an "AS IS" BASIS, | ||
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
201 | See the License for the specific language governing permissions and | ||
202 | limitations under the License. | ||
203 | |||
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 @@ | |||
1 | /* | ||
2 | * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/ | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include <algorithm> | ||
18 | |||
19 | #include <cstdint> | ||
20 | |||
21 | #include <cutils/log.h> | ||
22 | #include <cutils/properties.h> | ||
23 | |||
24 | #include "display.h" | ||
25 | #include "format.h" | ||
26 | #include "hwc_dev.h" | ||
27 | |||
28 | HWCDisplay::HWCDisplay(enum disp_role role) : | ||
29 | active_config(0), | ||
30 | role(role), | ||
31 | cb_procs(NULL), | ||
32 | is_dummy(false), | ||
33 | vsync_on(false), | ||
34 | blanked(true), | ||
35 | is_flip_pending(false) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | void HWCDisplay::setup_composition_pipes() | ||
40 | { | ||
41 | std::unique_lock<std::mutex> lock(this->mutex); | ||
42 | |||
43 | KMSDisplay* kdisp = &this->disp_link; | ||
44 | |||
45 | int count = 0; | ||
46 | for (auto plane : kdisp->card->get_planes()) { | ||
47 | auto possible_crtcs = plane->get_possible_crtcs(); | ||
48 | if (std::find(possible_crtcs.begin(), possible_crtcs.end(), kdisp->crtc) != possible_crtcs.end()) { | ||
49 | planeProps[count].plane = plane; | ||
50 | ALOGI("Overlay %d: plane_id: %d", count, planeProps[count].plane->id()); | ||
51 | count++; | ||
52 | } | ||
53 | } | ||
54 | } | ||
55 | |||
56 | /* Page flip handler callback */ | ||
57 | void HWCDisplay::page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data) | ||
58 | { | ||
59 | HWCDisplay* display = static_cast<HWCDisplay*>(data); | ||
60 | |||
61 | std::unique_lock<std::mutex> lock(display->mutex); | ||
62 | |||
63 | if (display->is_flip_pending == false) { | ||
64 | ALOGW("Spurious page flip?"); | ||
65 | return; | ||
66 | } | ||
67 | |||
68 | /* release the old buffers */ | ||
69 | for (auto current_fb_info : display->current_fb_infos) | ||
70 | delete current_fb_info; | ||
71 | display->current_fb_infos.clear(); | ||
72 | |||
73 | /* pending are now current */ | ||
74 | for (auto pending_fb_info : display->pending_fb_infos) | ||
75 | display->current_fb_infos.push_back(pending_fb_info); | ||
76 | display->pending_fb_infos.clear(); | ||
77 | |||
78 | display->is_flip_pending = false; | ||
79 | lock.unlock(); | ||
80 | display->cond_flip.notify_one(); | ||
81 | } | ||
82 | |||
83 | static int vblank_kick(HWCDisplay* display) | ||
84 | { | ||
85 | drmVBlank vblank; | ||
86 | memset(&vblank, 0, sizeof(vblank)); | ||
87 | vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT | | ||
88 | display->role == DISP_ROLE_SECONDARY ? DRM_VBLANK_SECONDARY : 0); | ||
89 | vblank.request.sequence = 1; | ||
90 | vblank.request.signal = (unsigned long)display; | ||
91 | int err = drmWaitVBlank(display->disp_link.card->fd(), &vblank); | ||
92 | if (err < 0) { | ||
93 | /* FIXME: error in drmWaitVBlank() use SW vsync instead? */ | ||
94 | ALOGE("drmWaitVBlank error %d (%s)", err, strerror(errno)); | ||
95 | return -1; | ||
96 | } | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | /* Callback function that gets triggered on vsync */ | ||
102 | void HWCDisplay::vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data) | ||
103 | { | ||
104 | HWCDisplay* display = static_cast<HWCDisplay*>(data); | ||
105 | |||
106 | std::unique_lock<std::mutex> lock(display->mutex); | ||
107 | |||
108 | if (display->vsync_on) { | ||
109 | int64_t ts = sec * (int64_t)1000000000 + usec * (int64_t)1000; | ||
110 | |||
111 | // ALOGD("Sending VBLANK at %lld for display %d", ts, display->role); | ||
112 | display->cb_procs->vsync(display->cb_procs, display->role, ts); | ||
113 | |||
114 | vblank_kick(display); | ||
115 | } | ||
116 | } | ||
117 | |||
118 | int HWCDisplay::set_vsync_state(bool state) | ||
119 | { | ||
120 | std::unique_lock<std::mutex> lock(this->mutex); | ||
121 | |||
122 | if (this->is_dummy) | ||
123 | return 0; | ||
124 | |||
125 | this->vsync_on = state; | ||
126 | |||
127 | if (this->vsync_on) | ||
128 | return vblank_kick(this); | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static void set_plane_properties(kms::AtomicReq& req, drm_plane_props_t* plane_props) | ||
134 | { | ||
135 | kms::Plane* plane = plane_props->plane; | ||
136 | |||
137 | req.add(plane, "FB_ID", plane_props->fb_info->fb_id); | ||
138 | |||
139 | req.add(plane, "IN_FENCE_FD", plane_props->layer->acquireFenceFd); | ||
140 | |||
141 | req.add(plane, { | ||
142 | { "CRTC_ID", plane_props->crtc_id }, | ||
143 | { "SRC_X", (plane_props->src_x) << 16 }, | ||
144 | { "SRC_Y", (plane_props->src_y) << 16 }, | ||
145 | { "SRC_W", (plane_props->src_w) << 16 }, | ||
146 | { "SRC_H", (plane_props->src_h) << 16 }, | ||
147 | { "CRTC_X", plane_props->crtc_x }, | ||
148 | { "CRTC_Y", plane_props->crtc_y }, | ||
149 | { "CRTC_W", plane_props->crtc_w }, | ||
150 | { "CRTC_H", plane_props->crtc_h }, | ||
151 | }); | ||
152 | |||
153 | /* optional props */ | ||
154 | req.add(plane, { | ||
155 | { "zorder", plane_props->zorder }, | ||
156 | { "pre_mult_alpha", plane_props->pre_mult_alpha }, | ||
157 | }); | ||
158 | } | ||
159 | |||
160 | int HWCDisplay::update_display(drm_plane_props_t* planeProp) | ||
161 | { | ||
162 | std::unique_lock<std::mutex> lock(this->mutex); | ||
163 | |||
164 | this->cond_flip.wait(lock, [this]{return !this->is_flip_pending;}); | ||
165 | |||
166 | buffer_handle_t handle = planeProp->layer->handle; | ||
167 | if (!handle) { | ||
168 | ALOGW("Got empty handle, nothing to display"); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | KMSDisplay* kdisp = &this->disp_link; | ||
173 | |||
174 | planeProp->fb_info = new DRMFramebuffer(kdisp->card->fd(), handle, false); | ||
175 | this->pending_fb_infos.push_back(planeProp->fb_info); | ||
176 | |||
177 | planeProp->crtc_id = kdisp->crtc->id(); | ||
178 | |||
179 | // Atomic display update | ||
180 | kms::AtomicReq req(*kdisp->card); | ||
181 | set_plane_properties(req, planeProp); | ||
182 | int ret = req.commit(this, true); | ||
183 | if (ret) { | ||
184 | ALOGE("cannot do atomic commit/page flip: %d (%s)", ret, strerror(errno)); | ||
185 | for (auto pending_fb_info : this->pending_fb_infos) | ||
186 | delete pending_fb_info; | ||
187 | this->pending_fb_infos.clear(); | ||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | // ALOGD("Scheduled page flip on display %d", this->role); | ||
192 | this->is_flip_pending = true; | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | void HWCDisplay::blank(int blank) | ||
198 | { | ||
199 | std::unique_lock<std::mutex> lock(this->mutex); | ||
200 | |||
201 | if (this->is_dummy) | ||
202 | return; | ||
203 | |||
204 | KMSDisplay* kdisp = &this->disp_link; | ||
205 | |||
206 | ALOGI("Linking connector %d to crtc %d", kdisp->con->id(), kdisp->crtc->id()); | ||
207 | |||
208 | int ret = kdisp->crtc->set_mode(kdisp->con, kdisp->mode); | ||
209 | if (ret) { | ||
210 | ALOGE("Failed to set crtc mode (%s)", strerror(-ret)); | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | // FIXME: This should actually blank the screen | ||
215 | this->blanked = blank; | ||
216 | } | ||
217 | |||
218 | int HWCDisplay::get_display_configs(uint32_t* configs, size_t* numConfigs) | ||
219 | { | ||
220 | if (!configs || !numConfigs) | ||
221 | return -EINVAL; | ||
222 | |||
223 | if (*numConfigs == 0) | ||
224 | return 0; | ||
225 | |||
226 | std::unique_lock<std::mutex> lock(this->mutex); | ||
227 | |||
228 | size_t num = this->configs.size(); | ||
229 | if (num > *numConfigs) | ||
230 | num = *numConfigs; | ||
231 | |||
232 | for (size_t i = 0; i < num; i++) | ||
233 | configs[i] = i; | ||
234 | |||
235 | *numConfigs = num; | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | int HWCDisplay::get_display_attributes(uint32_t cfg, const uint32_t* attributes, int32_t* values) | ||
241 | { | ||
242 | if (!attributes || !values) | ||
243 | return 0; | ||
244 | |||
245 | std::unique_lock<std::mutex> lock(this->mutex); | ||
246 | |||
247 | if (cfg >= this->configs.size()) | ||
248 | return -EINVAL; | ||
249 | |||
250 | display_config_t* config = &this->configs[cfg]; | ||
251 | |||
252 | for (size_t i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) { | ||
253 | switch (attributes[i]) { | ||
254 | case HWC_DISPLAY_VSYNC_PERIOD: | ||
255 | values[i] = 1000000000 / config->fps; | ||
256 | break; | ||
257 | case HWC_DISPLAY_WIDTH: | ||
258 | values[i] = config->xres; | ||
259 | break; | ||
260 | case HWC_DISPLAY_HEIGHT: | ||
261 | values[i] = config->yres; | ||
262 | break; | ||
263 | case HWC_DISPLAY_DPI_X: | ||
264 | values[i] = 1000 * config->xdpi; | ||
265 | break; | ||
266 | case HWC_DISPLAY_DPI_Y: | ||
267 | values[i] = 1000 * config->ydpi; | ||
268 | break; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | return 0; | ||
273 | } | ||
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 @@ | |||
1 | /* | ||
2 | * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/ | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #pragma once | ||
18 | |||
19 | #include <condition_variable> | ||
20 | #include <mutex> | ||
21 | |||
22 | #include <cstdbool> | ||
23 | #include <cstdint> | ||
24 | |||
25 | #include <hardware/hwcomposer.h> | ||
26 | #include <kms++/kms++.h> | ||
27 | |||
28 | #include <xf86drm.h> | ||
29 | #include <xf86drmMode.h> | ||
30 | |||
31 | #include "drmfb.h" | ||
32 | |||
33 | #define MAX_DISPLAYS 4 | ||
34 | #define DSS_AVAILABLE_PIPES 4 | ||
35 | |||
36 | typedef struct display_config { | ||
37 | unsigned int xres; | ||
38 | unsigned int yres; | ||
39 | unsigned int fps; | ||
40 | unsigned int xdpi; | ||
41 | unsigned int ydpi; | ||
42 | } display_config_t; | ||
43 | |||
44 | enum disp_role { | ||
45 | DISP_ROLE_PRIMARY = 0, | ||
46 | DISP_ROLE_SECONDARY, | ||
47 | }; | ||
48 | |||
49 | typedef struct drm_plane_props { | ||
50 | hwc_layer_1_t* layer; | ||
51 | |||
52 | kms::Plane* plane; | ||
53 | uint64_t crtc_id; | ||
54 | |||
55 | uint64_t crtc_x; | ||
56 | uint64_t crtc_y; | ||
57 | uint64_t crtc_w; | ||
58 | uint64_t crtc_h; | ||
59 | uint64_t src_x; | ||
60 | uint64_t src_y; | ||
61 | uint64_t src_w; | ||
62 | uint64_t src_h; | ||
63 | |||
64 | uint64_t rotation; | ||
65 | uint64_t zorder; | ||
66 | uint64_t pre_mult_alpha; | ||
67 | |||
68 | DRMFramebuffer* fb_info; | ||
69 | } drm_plane_props_t; | ||
70 | |||
71 | class KMSDisplay { | ||
72 | public: | ||
73 | KMSDisplay() : | ||
74 | card(NULL), | ||
75 | con(NULL), | ||
76 | crtc(NULL), | ||
77 | mode() {} | ||
78 | |||
79 | kms::Card* card; | ||
80 | kms::Connector* con; | ||
81 | kms::Crtc* crtc; | ||
82 | kms::Videomode mode; | ||
83 | }; | ||
84 | |||
85 | class HWCDisplay | ||
86 | { | ||
87 | public: | ||
88 | HWCDisplay(enum disp_role role); | ||
89 | ~HWCDisplay(){}; | ||
90 | |||
91 | void setup_composition_pipes(); | ||
92 | |||
93 | int update_display(drm_plane_props_t* planeProp); | ||
94 | |||
95 | std::vector<display_config_t> configs; | ||
96 | uint32_t active_config; | ||
97 | |||
98 | enum disp_role role; | ||
99 | |||
100 | drm_plane_props_t planeProps[DSS_AVAILABLE_PIPES]; | ||
101 | |||
102 | KMSDisplay disp_link; | ||
103 | |||
104 | const hwc_procs_t* cb_procs; | ||
105 | |||
106 | bool is_dummy; | ||
107 | |||
108 | int set_vsync_state(bool state); | ||
109 | void blank(int blank); | ||
110 | int get_display_configs(uint32_t* configs, size_t* numConfigs); | ||
111 | int get_display_attributes(uint32_t cfg, const uint32_t* attributes, int32_t* values); | ||
112 | |||
113 | static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data); | ||
114 | static void vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data); | ||
115 | |||
116 | private: | ||
117 | std::vector<DRMFramebuffer*> pending_fb_infos; | ||
118 | std::vector<DRMFramebuffer*> current_fb_infos; | ||
119 | |||
120 | bool vsync_on; | ||
121 | bool blanked; | ||
122 | |||
123 | std::mutex mutex; | ||
124 | std::condition_variable cond_flip; | ||
125 | volatile bool is_flip_pending; | ||
126 | }; | ||
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 @@ | |||
1 | /* | ||
2 | * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/ | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include <cutils/log.h> | ||
18 | #include <drm/drm_fourcc.h> | ||
19 | #include <hardware/hwcomposer.h> | ||
20 | |||
21 | #include <xf86drm.h> | ||
22 | #include <xf86drmMode.h> | ||
23 | |||
24 | #include "drmfb.h" | ||
25 | #include "format.h" | ||
26 | #include "hal_public.h" | ||
27 | |||
28 | DRMFramebuffer::DRMFramebuffer(int drm_fd, buffer_handle_t handle, bool is_overlay) : | ||
29 | bo(), pitches(), offsets() | ||
30 | { | ||
31 | if (!handle) | ||
32 | return; | ||
33 | |||
34 | uint32_t gem_handle; | ||
35 | IMG_native_handle_t* img_hnd = (IMG_native_handle_t*)handle; | ||
36 | int ret = drmPrimeFDToHandle(drm_fd, img_hnd->fd[0], &gem_handle); | ||
37 | if (ret) { | ||
38 | ALOGE("Failed to get DRM buffer object from handle"); | ||
39 | return; | ||
40 | } | ||
41 | |||
42 | this->width = img_hnd->iWidth; | ||
43 | this->height = img_hnd->iHeight; | ||
44 | this->format = convert_hal_to_drm_format(img_hnd->iFormat, true); | ||
45 | this->bo[0] = gem_handle; | ||
46 | this->pitches[0] = ALIGN(img_hnd->iWidth, HW_ALIGN) * get_format_bpp(img_hnd->iFormat) >> 3; | ||
47 | this->offsets[0] = 0; | ||
48 | this->drm_fd = drm_fd; | ||
49 | |||
50 | if (is_overlay) { | ||
51 | switch (this->format) { | ||
52 | case DRM_FORMAT_NV12: | ||
53 | this->bo[1] = gem_handle; | ||
54 | |||
55 | this->pitches[0] = ALIGN(img_hnd->iWidth, HW_ALIGN); | ||
56 | this->pitches[1] = this->pitches[0]; | ||
57 | |||
58 | this->offsets[1] = this->pitches[0] * img_hnd->iHeight; | ||
59 | break; | ||
60 | case DRM_FORMAT_ARGB8888: | ||
61 | case DRM_FORMAT_XRGB8888: | ||
62 | case DRM_FORMAT_RGB565: | ||
63 | break; | ||
64 | default: | ||
65 | ALOGE("Bad format for overlay"); | ||
66 | return; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | ret = drmModeAddFB2(drm_fd, this->width, this->height, | ||
71 | this->format, this->bo, | ||
72 | this->pitches, this->offsets, | ||
73 | &this->fb_id, 0); | ||
74 | if (ret) { | ||
75 | ALOGE("Could not create DRM frame buffer %d", ret); | ||
76 | return; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | DRMFramebuffer::~DRMFramebuffer() | ||
81 | { | ||
82 | if (this->fb_id) { | ||
83 | if (drmModeRmFB(this->drm_fd, this->fb_id)) | ||
84 | ALOGE("Failed to remove DRM frame buffer"); | ||
85 | } | ||
86 | |||
87 | for (size_t i = 0; i < 4; i++) { | ||
88 | if (this->bo[i]) { | ||
89 | struct drm_gem_close close_args = { | ||
90 | close_args.handle = this->bo[i], | ||
91 | close_args.pad = 0, | ||
92 | }; | ||
93 | int ret = drmIoctl(this->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_args); | ||
94 | if (ret) { | ||
95 | ALOGE("Failed to close GEM handle"); | ||
96 | return; | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | } | ||
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 @@ | |||
1 | /* | ||
2 | * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/ | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #pragma once | ||
18 | |||
19 | #include <cstdint> | ||
20 | |||
21 | class DRMFramebuffer | ||
22 | { | ||
23 | public: | ||
24 | DRMFramebuffer(int drm_fd, buffer_handle_t handle, bool is_overlay); | ||
25 | ~DRMFramebuffer(); | ||
26 | |||
27 | uint32_t width; | ||
28 | uint32_t height; | ||
29 | uint32_t format; | ||
30 | uint32_t bo[4]; | ||
31 | uint32_t pitches[4]; | ||
32 | uint32_t offsets[4]; | ||
33 | uint32_t fb_id; | ||
34 | int drm_fd; | ||
35 | }; | ||
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 @@ | |||
1 | /* | ||
2 | * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/ | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include <cstdint> | ||
18 | |||
19 | #include <cutils/log.h> | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | |||
23 | #include "format.h" | ||
24 | #include "hal_public.h" | ||
25 | |||
26 | bool is_valid_format(uint32_t format) | ||
27 | { | ||
28 | switch (format) { | ||
29 | case HAL_PIXEL_FORMAT_RGBA_8888: | ||
30 | case HAL_PIXEL_FORMAT_BGRA_8888: | ||
31 | return true; | ||
32 | |||
33 | case HAL_PIXEL_FORMAT_RGB_565: | ||
34 | return true; | ||
35 | |||
36 | case HAL_PIXEL_FORMAT_NV12: | ||
37 | return true; | ||
38 | |||
39 | case HAL_PIXEL_FORMAT_RGBX_8888: | ||
40 | case HAL_PIXEL_FORMAT_BGRX_8888: | ||
41 | return true; | ||
42 | |||
43 | case HAL_PIXEL_FORMAT_TI_NV12: | ||
44 | case HAL_PIXEL_FORMAT_TI_NV12_1D: | ||
45 | /* legacy formats not supported anymore */ | ||
46 | return false; | ||
47 | |||
48 | default: | ||
49 | return false; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | bool is_rgb_format(uint32_t format) | ||
54 | { | ||
55 | switch (format) { | ||
56 | case HAL_PIXEL_FORMAT_BGRA_8888: | ||
57 | case HAL_PIXEL_FORMAT_BGRX_8888: | ||
58 | case HAL_PIXEL_FORMAT_RGB_565: | ||
59 | return true; | ||
60 | default: | ||
61 | return false; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | bool is_bgr_format(uint32_t format) | ||
66 | { | ||
67 | switch (format) { | ||
68 | case HAL_PIXEL_FORMAT_RGBX_8888: | ||
69 | case HAL_PIXEL_FORMAT_RGBA_8888: | ||
70 | return true; | ||
71 | default: | ||
72 | return false; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | bool is_nv12_format(uint32_t format) | ||
77 | { | ||
78 | switch (format) { | ||
79 | case HAL_PIXEL_FORMAT_TI_NV12: | ||
80 | case HAL_PIXEL_FORMAT_TI_NV12_1D: | ||
81 | case HAL_PIXEL_FORMAT_NV12: | ||
82 | return true; | ||
83 | default: | ||
84 | return false; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | bool is_opaque_format(uint32_t format) | ||
89 | { | ||
90 | switch (format) { | ||
91 | case HAL_PIXEL_FORMAT_RGB_565: | ||
92 | case HAL_PIXEL_FORMAT_RGBX_8888: | ||
93 | case HAL_PIXEL_FORMAT_BGRX_8888: | ||
94 | return true; | ||
95 | default: | ||
96 | return false; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | uint32_t get_format_bpp(uint32_t format) | ||
101 | { | ||
102 | switch (format) { | ||
103 | case HAL_PIXEL_FORMAT_BGRA_8888: | ||
104 | case HAL_PIXEL_FORMAT_BGRX_8888: | ||
105 | case HAL_PIXEL_FORMAT_RGBX_8888: | ||
106 | case HAL_PIXEL_FORMAT_RGBA_8888: | ||
107 | return 32; | ||
108 | case HAL_PIXEL_FORMAT_RGB_565: | ||
109 | return 16; | ||
110 | case HAL_PIXEL_FORMAT_TI_NV12: | ||
111 | case HAL_PIXEL_FORMAT_TI_NV12_1D: | ||
112 | case HAL_PIXEL_FORMAT_NV12: | ||
113 | return 8; | ||
114 | default: | ||
115 | return 0; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | uint32_t convert_hal_to_drm_format(uint32_t hal_format, bool blended) | ||
120 | { | ||
121 | uint32_t dss_format = HAL_PIXEL_FORMAT_RGBA_8888; | ||
122 | |||
123 | /* convert color format */ | ||
124 | switch (hal_format) { | ||
125 | case HAL_PIXEL_FORMAT_RGBA_8888: | ||
126 | case HAL_PIXEL_FORMAT_BGRA_8888: | ||
127 | dss_format = DRM_FORMAT_ARGB8888; | ||
128 | if (blended) | ||
129 | break; | ||
130 | |||
131 | case HAL_PIXEL_FORMAT_RGBX_8888: | ||
132 | case HAL_PIXEL_FORMAT_BGRX_8888: | ||
133 | dss_format = DRM_FORMAT_XRGB8888; | ||
134 | break; | ||
135 | |||
136 | case HAL_PIXEL_FORMAT_RGB_565: | ||
137 | dss_format = DRM_FORMAT_RGB565; | ||
138 | break; | ||
139 | |||
140 | case HAL_PIXEL_FORMAT_TI_NV12: | ||
141 | case HAL_PIXEL_FORMAT_TI_NV12_1D: | ||
142 | case HAL_PIXEL_FORMAT_NV12: | ||
143 | dss_format = DRM_FORMAT_NV12; | ||
144 | break; | ||
145 | |||
146 | default: | ||
147 | /* Should have been filtered out */ | ||
148 | ALOGV("Unsupported pixel format"); | ||
149 | } | ||
150 | |||
151 | return dss_format; | ||
152 | } | ||
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 @@ | |||
1 | /* | ||
2 | * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/ | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #pragma once | ||
18 | |||
19 | #include <string> | ||
20 | |||
21 | #include <cstdint> | ||
22 | |||
23 | #include <drm/drm_fourcc.h> | ||
24 | #include <linux/types.h> | ||
25 | |||
26 | #include "hal_public.h" | ||
27 | |||
28 | static inline std::string HAL_FMT(uint32_t format) | ||
29 | { | ||
30 | switch (format) { | ||
31 | case HAL_PIXEL_FORMAT_TI_NV12: return "NV12"; | ||
32 | case HAL_PIXEL_FORMAT_TI_NV12_1D: return "NV12"; | ||
33 | case HAL_PIXEL_FORMAT_YV12: return "YV12"; | ||
34 | case HAL_PIXEL_FORMAT_BGRX_8888: return "xRGB32"; | ||
35 | case HAL_PIXEL_FORMAT_RGBX_8888: return "xBGR32"; | ||
36 | case HAL_PIXEL_FORMAT_BGRA_8888: return "ARGB32"; | ||
37 | case HAL_PIXEL_FORMAT_RGBA_8888: return "ABGR32"; | ||
38 | case HAL_PIXEL_FORMAT_RGB_565: return "RGB565"; | ||
39 | default: return "??"; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static inline std::string DRM_FMT(uint32_t format) | ||
44 | { | ||
45 | switch (format) { | ||
46 | case DRM_FORMAT_NV12: return "NV12"; | ||
47 | case DRM_FORMAT_XRGB8888: return "xRGB32"; | ||
48 | case DRM_FORMAT_ARGB8888: return "ARGB32"; | ||
49 | case DRM_FORMAT_RGB565: return "RGB565"; | ||
50 | default: return "??"; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | bool is_valid_format(uint32_t format); | ||
55 | bool is_rgb_format(uint32_t format); | ||
56 | bool is_bgr_format(uint32_t format); | ||
57 | bool is_nv12_format(uint32_t format); | ||
58 | bool is_opaque_format(uint32_t format); | ||
59 | uint32_t get_format_bpp(uint32_t format); | ||
60 | uint32_t convert_hal_to_dss_format(uint32_t format, bool blended); | ||
61 | uint32_t convert_hal_to_drm_format(uint32_t hal_format, bool blended); | ||
62 | uint32_t convert_hal_to_ocd_format(uint32_t hal_format); | ||
63 | 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 @@ | |||
1 | /* Copyright (c) Imagination Technologies Ltd. | ||
2 | * | ||
3 | * The contents of this file are subject to the MIT license as set out below. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | * of this software and associated documentation files (the "Software"), to deal | ||
7 | * in the Software without restriction, including without limitation the rights | ||
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | * copies of the Software, and to permit persons to whom the Software is | ||
10 | * furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice shall be included in | ||
13 | * all copies or substantial portions of the Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | * THE SOFTWARE. | ||
22 | */ | ||
23 | |||
24 | #ifndef HAL_PUBLIC_H | ||
25 | #define HAL_PUBLIC_H | ||
26 | |||
27 | /* Authors of third party hardware composer (HWC) modules will need to include | ||
28 | * this header to access functionality in the gralloc and framebuffer HALs. | ||
29 | */ | ||
30 | |||
31 | #include <hardware/gralloc.h> | ||
32 | #include <hardware/memtrack.h> | ||
33 | |||
34 | #define ALIGN(x,a) (((x) + (a) - 1L) & ~((a) - 1L)) | ||
35 | #define HW_ALIGN 16 | ||
36 | |||
37 | /* This can be tuned down as appropriate for the SOC. | ||
38 | * | ||
39 | * IMG formats are usually a single sub-alloc. | ||
40 | * Some OEM video formats are two sub-allocs (Y, UV planes). | ||
41 | * Future OEM video formats might be three sub-allocs (Y, U, V planes). | ||
42 | */ | ||
43 | #define MAX_SUB_ALLOCS 3 | ||
44 | |||
45 | /* Format is not YCbCr (e.g. a RGB format) - bIsYUVFormat should be false */ | ||
46 | #define YUV_CHROMA_ORDER_NONE 0 | ||
47 | /* Cb follows Y */ | ||
48 | #define YUV_CHROMA_ORDER_CBCR_UV 1 | ||
49 | /* Cr follows Y */ | ||
50 | #define YUV_CHROMA_ORDER_CRCB_VU 2 | ||
51 | |||
52 | typedef struct | ||
53 | { | ||
54 | native_handle_t base; | ||
55 | |||
56 | /* These fields can be sent cross process. They are also valid | ||
57 | * to duplicate within the same process. | ||
58 | * | ||
59 | * A table is stored within psPrivateData on gralloc_module_t (this | ||
60 | * is obviously per-process) which maps stamps to a mapped | ||
61 | * PVRSRV_CLIENT_MEM_INFO in that process. Each map entry has a lock | ||
62 | * count associated with it, satisfying the requirements of the | ||
63 | * Android API. This also prevents us from leaking maps/allocations. | ||
64 | * | ||
65 | * This table has entries inserted either by alloc() | ||
66 | * (alloc_device_t) or map() (gralloc_module_t). Entries are removed | ||
67 | * by free() (alloc_device_t) and unmap() (gralloc_module_t). | ||
68 | * | ||
69 | * As a special case for framebuffer_device_t, framebuffer_open() | ||
70 | * will add and framebuffer_close() will remove from this table. | ||
71 | */ | ||
72 | |||
73 | #define IMG_NATIVE_HANDLE_NUMFDS MAX_SUB_ALLOCS | ||
74 | /* The `fd' field is used to "export" a meminfo to another process. | ||
75 | * Therefore, it is allocated by alloc_device_t, and consumed by | ||
76 | * gralloc_module_t. The framebuffer_device_t does not need a handle, | ||
77 | * and the special value IMG_FRAMEBUFFER_FD is used instead. | ||
78 | */ | ||
79 | int fd[MAX_SUB_ALLOCS]; | ||
80 | |||
81 | #define IMG_NATIVE_HANDLE_NUMINTS \ | ||
82 | ((sizeof(unsigned long long) / sizeof(int)) + 5 + MAX_SUB_ALLOCS + 1 + MAX_SUB_ALLOCS + MAX_SUB_ALLOCS) | ||
83 | /* A KERNEL unique identifier for any exported kernel meminfo. Each | ||
84 | * exported kernel meminfo will have a unique stamp, but note that in | ||
85 | * userspace, several meminfos across multiple processes could have | ||
86 | * the same stamp. As the native_handle can be dup(2)'d, there could be | ||
87 | * multiple handles with the same stamp but different file descriptors. | ||
88 | */ | ||
89 | unsigned long long ui64Stamp; | ||
90 | |||
91 | /* This is used for buffer usage validation when locking a buffer, | ||
92 | * and also in WSEGL (for the composition bypass feature). | ||
93 | */ | ||
94 | int usage; | ||
95 | |||
96 | /* In order to do efficient cache flushes we need the buffer dimensions | ||
97 | * and format. These are available on the ANativeWindowBuffer, | ||
98 | * but the platform doesn't pass them down to the graphics HAL. | ||
99 | */ | ||
100 | int iWidth; | ||
101 | int iHeight; | ||
102 | int iFormat; | ||
103 | unsigned int uiBpp; | ||
104 | |||
105 | /* The ion allocation path doesn't allow for the allocation size and | ||
106 | * mapping flags to be communicated cross-process automatically. | ||
107 | * Cache these here so we can map buffers in client processes. | ||
108 | */ | ||
109 | unsigned int uiAllocSize[MAX_SUB_ALLOCS]; | ||
110 | unsigned int uiFlags; | ||
111 | /* For multi-planar allocations, there will be multiple hstrides */ | ||
112 | int aiStride[MAX_SUB_ALLOCS]; | ||
113 | |||
114 | /* For multi-planar allocations, there will be multiple vstrides */ | ||
115 | int aiVStride[MAX_SUB_ALLOCS]; | ||
116 | |||
117 | } | ||
118 | __attribute__((aligned(sizeof(int)),packed)) IMG_native_handle_t; | ||
119 | |||
120 | typedef struct | ||
121 | { | ||
122 | int l, t, w, h; | ||
123 | } | ||
124 | IMG_write_lock_rect_t; | ||
125 | |||
126 | typedef int (*IMG_buffer_format_compute_params_pfn)( | ||
127 | unsigned int uiPlane, int *piWidth, int *piHeight, | ||
128 | int *piStride, int *piVStride, unsigned long *pulPlaneOffset); | ||
129 | |||
130 | typedef struct IMG_buffer_format_public_t | ||
131 | { | ||
132 | /* Buffer formats are returned as a linked list */ | ||
133 | struct IMG_buffer_format_public_t *psNext; | ||
134 | |||
135 | /* HAL_PIXEL_FORMAT_... enumerant */ | ||
136 | int iHalPixelFormat; | ||
137 | |||
138 | /* WSEGL_PIXELFORMAT_... enumerant */ | ||
139 | int iWSEGLPixelFormat; | ||
140 | |||
141 | /* Friendly name for format */ | ||
142 | const char *const szName; | ||
143 | |||
144 | /* Bits (not bytes) per pixel */ | ||
145 | unsigned int uiBpp; | ||
146 | |||
147 | /* Supported HW usage bits. If this is GRALLOC_USAGE_HW_MASK, all usages | ||
148 | * are supported. Used for HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED. | ||
149 | */ | ||
150 | int iSupportedUsage; | ||
151 | |||
152 | /* YUV output format */ | ||
153 | int bIsYUVFormat; | ||
154 | |||
155 | /* YCBCR_ORDERING_* defined the order of the Cb/Cr values */ | ||
156 | int eYUVChromaOrder; | ||
157 | |||
158 | /* Utility function for adjusting YUV per-plane parameters */ | ||
159 | IMG_buffer_format_compute_params_pfn pfnComputeParams; | ||
160 | } | ||
161 | IMG_buffer_format_public_t; | ||
162 | |||
163 | typedef struct | ||
164 | { | ||
165 | /* Base memtrack record, copied to caller */ | ||
166 | struct memtrack_record base; | ||
167 | |||
168 | /* Record type, for filtering cached records */ | ||
169 | enum memtrack_type eType; | ||
170 | |||
171 | /* Process ID, for filtering cached records */ | ||
172 | pid_t pid; | ||
173 | } | ||
174 | IMG_memtrack_record_public_t; | ||
175 | |||
176 | typedef struct IMG_gralloc_module_public_t | ||
177 | { | ||
178 | gralloc_module_t base; | ||
179 | |||
180 | /* This function is deprecated and might be NULL. Do not use it. */ | ||
181 | int (*GetPhyAddrs)(gralloc_module_t const* module, | ||
182 | buffer_handle_t handle, void **ppvPhyAddr); | ||
183 | |||
184 | /* Obtain HAL's registered format list */ | ||
185 | const IMG_buffer_format_public_t *(*GetBufferFormats)(void); | ||
186 | |||
187 | int (*GetImplementationFormat) (struct IMG_gralloc_module_public_t const *psGrallocModule, int usage); | ||
188 | |||
189 | int (*GetMemTrackRecords)(struct IMG_gralloc_module_public_t const *module, | ||
190 | IMG_memtrack_record_public_t **ppsRecords, | ||
191 | size_t *puNumRecords); | ||
192 | |||
193 | /* Custom-blit components in lieu of overlay hardware */ | ||
194 | int (*Blit)(struct IMG_gralloc_module_public_t const *module, | ||
195 | buffer_handle_t src, | ||
196 | void *dest[MAX_SUB_ALLOCS], int format); | ||
197 | |||
198 | int (*Blit2)(struct IMG_gralloc_module_public_t const *module, | ||
199 | buffer_handle_t src, buffer_handle_t dest, | ||
200 | int w, int h, int x, int y); | ||
201 | |||
202 | int (*Blit3)(struct IMG_gralloc_module_public_t const *module, | ||
203 | unsigned long long ui64SrcStamp, int iSrcWidth, | ||
204 | int iSrcHeight, int iSrcFormat, int eSrcRotation, | ||
205 | buffer_handle_t dest, int eDestRotation); | ||
206 | } | ||
207 | IMG_gralloc_module_public_t; | ||
208 | |||
209 | /** | ||
210 | * pixel format definitions | ||
211 | */ | ||
212 | |||
213 | enum { | ||
214 | /* | ||
215 | * 0x100 = 0x1FF | ||
216 | * | ||
217 | * This range is reserved for pixel formats that are specific to the HAL | ||
218 | * implementation. Implementations can use any value in this range to | ||
219 | * communicate video pixel formats between their HAL modules. These | ||
220 | * formats must not have an alpha channel. Additionally, an EGLimage | ||
221 | * created from a gralloc buffer of one of these formats must be | ||
222 | * supported for use with the GL_OES_EGL_image_external OpenGL ES | ||
223 | * extension. | ||
224 | */ | ||
225 | |||
226 | /* | ||
227 | * These are vendor specific pixel format, by (informal) convention | ||
228 | * IMGTec formats start from the top of the range, TI formats start from | ||
229 | * the bottom | ||
230 | */ | ||
231 | HAL_PIXEL_FORMAT_TI_NV12 = 0x100, | ||
232 | HAL_PIXEL_FORMAT_TI_UNUSED = 0x101, | ||
233 | HAL_PIXEL_FORMAT_TI_NV12_1D = 0x102, | ||
234 | HAL_PIXEL_FORMAT_TI_Y8 = 0x103, | ||
235 | HAL_PIXEL_FORMAT_TI_Y16 = 0x104, | ||
236 | HAL_PIXEL_FORMAT_TI_UYVY = 0x105, | ||
237 | HAL_PIXEL_FORMAT_BGRX_8888 = 0x1FF, | ||
238 | |||
239 | /* generic format missing from Android list, not specific to vendor | ||
240 | * implementation | ||
241 | */ | ||
242 | HAL_PIXEL_FORMAT_NV12 = 0x3231564E, // FourCC for NV12 | ||
243 | }; | ||
244 | |||
245 | #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 @@ | |||
1 | /* | ||
2 | * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/ | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include <sstream> | ||
18 | |||
19 | #include <cutils/trace.h> | ||
20 | #include <fcntl.h> | ||
21 | #include <poll.h> | ||
22 | #include <sys/ioctl.h> | ||
23 | #include <sys/resource.h> | ||
24 | |||
25 | #include <cutils/log.h> | ||
26 | #include <cutils/properties.h> | ||
27 | #define HWC_REMOVE_DEPRECATED_VERSIONS 1 | ||
28 | #include <hardware/hardware.h> | ||
29 | #include <hardware/hwcomposer.h> | ||
30 | #include <hardware_legacy/uevent.h> | ||
31 | |||
32 | #include <kms++/kms++.h> | ||
33 | |||
34 | #include "display.h" | ||
35 | #include "format.h" | ||
36 | #include "hwc_dev.h" | ||
37 | |||
38 | #define LCD_DISPLAY_DEFAULT_HRES 1920 | ||
39 | #define LCD_DISPLAY_DEFAULT_VRES 1080 | ||
40 | #define LCD_DISPLAY_DEFAULT_FPS 60 | ||
41 | |||
42 | #define LCD_DISPLAY_DEFAULT_DPI 120 | ||
43 | #define HDMI_DISPLAY_DEFAULT_DPI 75 | ||
44 | |||
45 | #define HWC_PRIORITY_LOW_DISPLAY (19) | ||
46 | |||
47 | #ifndef ARRAY_SIZE | ||
48 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
49 | #endif | ||
50 | |||
51 | #define WIDTH(rect) ((rect).right - (rect).left) | ||
52 | #define HEIGHT(rect) ((rect).bottom - (rect).top) | ||
53 | |||
54 | static bool is_valid_display(omap_hwc_device_t* hwc_dev, int disp) | ||
55 | { | ||
56 | if (disp < 0 || disp >= MAX_DISPLAYS || !hwc_dev->displays[disp]) | ||
57 | return false; | ||
58 | |||
59 | return true; | ||
60 | } | ||
61 | |||
62 | struct drm_connector_type { | ||
63 | int type; | ||
64 | char name[64]; | ||
65 | }; | ||
66 | |||
67 | #define CONNECTOR_TYPE_STR(type) { DRM_MODE_CONNECTOR_ ## type, #type } | ||
68 | |||
69 | static const struct drm_connector_type connector_type_list[] = { | ||
70 | CONNECTOR_TYPE_STR(Unknown), | ||
71 | CONNECTOR_TYPE_STR(VGA), | ||
72 | CONNECTOR_TYPE_STR(DVII), | ||
73 | CONNECTOR_TYPE_STR(DVID), | ||
74 | CONNECTOR_TYPE_STR(DVIA), | ||
75 | CONNECTOR_TYPE_STR(Composite), | ||
76 | CONNECTOR_TYPE_STR(SVIDEO), | ||
77 | CONNECTOR_TYPE_STR(LVDS), | ||
78 | CONNECTOR_TYPE_STR(Component), | ||
79 | CONNECTOR_TYPE_STR(9PinDIN), | ||
80 | CONNECTOR_TYPE_STR(DisplayPort), | ||
81 | CONNECTOR_TYPE_STR(HDMIA), | ||
82 | CONNECTOR_TYPE_STR(HDMIB), | ||
83 | CONNECTOR_TYPE_STR(TV), | ||
84 | CONNECTOR_TYPE_STR(eDP), | ||
85 | CONNECTOR_TYPE_STR(VIRTUAL), | ||
86 | CONNECTOR_TYPE_STR(DSI), | ||
87 | CONNECTOR_TYPE_STR(DPI), | ||
88 | }; | ||
89 | |||
90 | /* The connectors for primary and external displays can be controlled | ||
91 | * by the below system properties | ||
92 | * - ro.hwc.primary.conn | ||
93 | * - ro.hwc.external.conn | ||
94 | * If these are not set (default), `DRM_CONNECTOR_TYPE_Unknown` will be | ||
95 | * considered as primary display connector, and `DRM_CONNECTOR_TYPE_HDMIA` | ||
96 | * will be considered as secondary display. | ||
97 | * | ||
98 | * The values are <string> constants, with acceptable values being as defined | ||
99 | * by the DRM interface `DRM_CONNECTOR_TYPE_<string>`. | ||
100 | * | ||
101 | * If nothing is set, external is `HDMIA` connector. | ||
102 | */ | ||
103 | static int display_get_connector_type(int disp) | ||
104 | { | ||
105 | char prop_val[PROPERTY_VALUE_MAX]; | ||
106 | |||
107 | if (disp == HWC_DISPLAY_PRIMARY) | ||
108 | property_get("ro.hwc.primary.conn", prop_val, ""); | ||
109 | else | ||
110 | property_get("ro.hwc.external.conn", prop_val, "HDMIA"); | ||
111 | |||
112 | for (size_t i = 0; i < ARRAY_SIZE(connector_type_list); i++) { | ||
113 | if (!strncasecmp(prop_val, connector_type_list[i].name, 64)) | ||
114 | return connector_type_list[i].type; | ||
115 | } | ||
116 | |||
117 | return -1; | ||
118 | } | ||
119 | |||
120 | static void get_connectors(omap_hwc_device_t* hwc_dev) | ||
121 | { | ||
122 | int primary_connector_type = display_get_connector_type(HWC_DISPLAY_PRIMARY); | ||
123 | int external_connector_type = display_get_connector_type(HWC_DISPLAY_EXTERNAL); | ||
124 | |||
125 | // Find primary connector | ||
126 | for (auto connector : hwc_dev->card->get_connectors()) { | ||
127 | if (primary_connector_type != -1) { | ||
128 | if (connector->connector_type() == (uint32_t)primary_connector_type) { | ||
129 | hwc_dev->primaryConector = connector; | ||
130 | break; | ||
131 | } | ||
132 | } else { | ||
133 | /* If connector type is not specified use the first | ||
134 | * connector that is not our HWC_DISPLAY_EXTERNAL connector | ||
135 | */ | ||
136 | if (connector->connector_type() != (uint32_t)external_connector_type) { | ||
137 | hwc_dev->primaryConector = connector; | ||
138 | break; | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | |||
143 | // Find external connector | ||
144 | for (auto connector : hwc_dev->card->get_connectors()) { | ||
145 | if (connector->connector_type() == (uint32_t)external_connector_type) { | ||
146 | hwc_dev->externalConector = connector; | ||
147 | break; | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | |||
152 | static int init_primary_display(omap_hwc_device_t* hwc_dev) | ||
153 | { | ||
154 | if (hwc_dev->displays[HWC_DISPLAY_PRIMARY]) { | ||
155 | ALOGE("Display %d is already connected", HWC_DISPLAY_PRIMARY); | ||
156 | return -EBUSY; | ||
157 | } | ||
158 | |||
159 | kms::Connector* connector = hwc_dev->primaryConector; | ||
160 | |||
161 | HWCDisplay* display = new HWCDisplay(DISP_ROLE_PRIMARY); | ||
162 | hwc_dev->displays[HWC_DISPLAY_PRIMARY] = display; | ||
163 | |||
164 | if (!connector) { | ||
165 | ALOGW("No connector found for primary display"); | ||
166 | ALOGW("Using dummy primary display"); | ||
167 | |||
168 | display->is_dummy = true; | ||
169 | |||
170 | display_config_t config; | ||
171 | config.xres = LCD_DISPLAY_DEFAULT_HRES; | ||
172 | config.yres = LCD_DISPLAY_DEFAULT_VRES; | ||
173 | config.fps = LCD_DISPLAY_DEFAULT_FPS; | ||
174 | config.xdpi = LCD_DISPLAY_DEFAULT_DPI; | ||
175 | config.ydpi = LCD_DISPLAY_DEFAULT_DPI; | ||
176 | display->configs.push_back(config); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | /* Always use default mode for now */ | ||
182 | kms::Videomode mode = connector->get_default_mode(); | ||
183 | |||
184 | display_config_t config; | ||
185 | config.xres = mode.hdisplay; | ||
186 | config.yres = mode.vdisplay; | ||
187 | config.fps = mode.vrefresh; | ||
188 | config.xdpi = LCD_DISPLAY_DEFAULT_DPI; | ||
189 | config.ydpi = LCD_DISPLAY_DEFAULT_DPI; | ||
190 | display->configs.push_back(config); | ||
191 | |||
192 | display->disp_link.card = hwc_dev->card; | ||
193 | display->disp_link.con = connector; | ||
194 | display->disp_link.crtc = connector->get_current_crtc(); | ||
195 | // FIXME: user resource manager | ||
196 | if (!display->disp_link.crtc) | ||
197 | display->disp_link.crtc = connector->get_possible_crtcs()[0]; | ||
198 | display->disp_link.mode = mode; | ||
199 | |||
200 | display->setup_composition_pipes(); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int add_external_hdmi_display(omap_hwc_device_t* hwc_dev) | ||
206 | { | ||
207 | if (hwc_dev->displays[HWC_DISPLAY_EXTERNAL]) { | ||
208 | ALOGE("Display %d is already connected", HWC_DISPLAY_EXTERNAL); | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | kms::Connector* connector = hwc_dev->externalConector; | ||
213 | |||
214 | if (!connector) { | ||
215 | ALOGE("No connector for external display"); | ||
216 | return -1; | ||
217 | } | ||
218 | |||
219 | /* wait until EDID read finishes */ | ||
220 | do { | ||
221 | connector->refresh(); | ||
222 | } while (connector->get_modes().size() == 0); | ||
223 | |||
224 | // FIXME: Allow selecting other modes until HWC 1.4 support is added | ||
225 | kms::Videomode mode = connector->get_default_mode(); | ||
226 | |||
227 | HWCDisplay* display = new HWCDisplay(DISP_ROLE_SECONDARY); | ||
228 | hwc_dev->displays[HWC_DISPLAY_EXTERNAL] = display; | ||
229 | |||
230 | display_config_t config; | ||
231 | config.xres = mode.hdisplay; | ||
232 | config.yres = mode.vdisplay; | ||
233 | config.fps = mode.vrefresh; | ||
234 | config.xdpi = HDMI_DISPLAY_DEFAULT_DPI; | ||
235 | config.ydpi = HDMI_DISPLAY_DEFAULT_DPI; | ||
236 | display->configs.push_back(config); | ||
237 | |||
238 | display->disp_link.card = hwc_dev->card; | ||
239 | display->disp_link.con = connector; | ||
240 | display->disp_link.crtc = connector->get_current_crtc(); | ||
241 | // FIXME: user resource manager | ||
242 | if (!display->disp_link.crtc) | ||
243 | display->disp_link.crtc = connector->get_possible_crtcs()[0]; | ||
244 | display->disp_link.mode = mode; | ||
245 | |||
246 | display->setup_composition_pipes(); | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static void remove_external_hdmi_display(omap_hwc_device_t* hwc_dev) | ||
252 | { | ||
253 | HWCDisplay* display = hwc_dev->displays[HWC_DISPLAY_EXTERNAL]; | ||
254 | if (!display) { | ||
255 | ALOGW("Failed to remove non-existent display %d", HWC_DISPLAY_EXTERNAL); | ||
256 | return; | ||
257 | } | ||
258 | |||
259 | delete hwc_dev->displays[HWC_DISPLAY_EXTERNAL]; | ||
260 | hwc_dev->displays[HWC_DISPLAY_EXTERNAL] = NULL; | ||
261 | } | ||
262 | |||
263 | static void handle_hotplug(omap_hwc_device_t* hwc_dev, bool state) | ||
264 | { | ||
265 | if (state) { | ||
266 | int err = add_external_hdmi_display(hwc_dev); | ||
267 | if (err) { | ||
268 | remove_external_hdmi_display(hwc_dev); | ||
269 | return; | ||
270 | } | ||
271 | ALOGI("Added external display"); | ||
272 | } else { | ||
273 | remove_external_hdmi_display(hwc_dev); | ||
274 | ALOGI("Removed external display"); | ||
275 | } | ||
276 | } | ||
277 | |||
278 | static int find_hdmi_connector_status(omap_hwc_device_t* hwc_dev) | ||
279 | { | ||
280 | auto connector = hwc_dev->externalConector; | ||
281 | if (!connector) | ||
282 | return false; | ||
283 | |||
284 | bool old_state = connector->connected(); | ||
285 | connector->refresh(); | ||
286 | bool cur_state = connector->connected(); | ||
287 | |||
288 | if (cur_state != old_state) | ||
289 | ALOGI("%s event for connector %u\n", | ||
290 | cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", | ||
291 | connector->id()); | ||
292 | |||
293 | return cur_state == DRM_MODE_CONNECTED; | ||
294 | } | ||
295 | |||
296 | static bool check_hotplug_status(omap_hwc_device_t* hwc_dev, bool old_state) | ||
297 | { | ||
298 | std::unique_lock<std::mutex> lock(hwc_dev->mutex); | ||
299 | |||
300 | bool state = find_hdmi_connector_status(hwc_dev); | ||
301 | if (state != old_state) | ||
302 | handle_hotplug(hwc_dev, state); | ||
303 | |||
304 | lock.unlock(); | ||
305 | |||
306 | if (hwc_dev->cb_procs) { | ||
307 | if (hwc_dev->cb_procs->hotplug) | ||
308 | hwc_dev->cb_procs->hotplug(hwc_dev->cb_procs, HWC_DISPLAY_EXTERNAL, state); | ||
309 | if (hwc_dev->cb_procs->invalidate) | ||
310 | hwc_dev->cb_procs->invalidate(hwc_dev->cb_procs); | ||
311 | } | ||
312 | |||
313 | return state; | ||
314 | } | ||
315 | |||
316 | static void hwc_hdmi_thread(void* data) | ||
317 | { | ||
318 | omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)data; | ||
319 | |||
320 | setpriority(PRIO_PROCESS, 0, HWC_PRIORITY_LOW_DISPLAY); | ||
321 | |||
322 | uevent_init(); | ||
323 | |||
324 | struct pollfd pfds[1] = { | ||
325 | { | ||
326 | pfds[0].fd = uevent_get_fd(), | ||
327 | pfds[0].events = POLLIN, | ||
328 | pfds[0].revents = 0, | ||
329 | } | ||
330 | }; | ||
331 | |||
332 | const char* hdmi_uevent_path = "change@/devices/platform/omapdrm.0/drm/card0"; | ||
333 | static char uevent_desc[4096]; | ||
334 | memset(uevent_desc, 0, sizeof(uevent_desc)); | ||
335 | |||
336 | /* Check outside of uevent loop in-case already plugged in */ | ||
337 | bool state = check_hotplug_status(hwc_dev, false); | ||
338 | |||
339 | while (true) { | ||
340 | int err = poll(pfds, ARRAY_SIZE(pfds), -1); | ||
341 | if (err < 0) { | ||
342 | ALOGE("received hdmi_thread poll() error event %d", err); | ||
343 | break; | ||
344 | } | ||
345 | |||
346 | if (pfds[0].revents & POLLIN) { | ||
347 | /* keep last 2 zeroes to ensure double 0 termination */ | ||
348 | uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2); | ||
349 | if (strlen(hdmi_uevent_path) <= 0 || strcmp(uevent_desc, hdmi_uevent_path)) | ||
350 | continue; /* event not for us */ | ||
351 | |||
352 | state = check_hotplug_status(hwc_dev, state); | ||
353 | } | ||
354 | } | ||
355 | |||
356 | ALOGE("HDMI polling thread exiting\n"); | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * DRM event polling thread | ||
361 | * We poll for DRM events in this thread. DRM events can be vblank and/or | ||
362 | * page-flip events both occurring on Vsync. | ||
363 | */ | ||
364 | static void hwc_drm_event_thread(void* data) | ||
365 | { | ||
366 | omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)data; | ||
367 | |||
368 | setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); | ||
369 | |||
370 | struct pollfd pfds = { | ||
371 | pfds.fd = hwc_dev->card->fd(), | ||
372 | pfds.events = POLLIN, | ||
373 | pfds.revents = 0, | ||
374 | }; | ||
375 | |||
376 | drmEventContext evctx = { | ||
377 | evctx.version = 2, | ||
378 | evctx.vblank_handler = HWCDisplay::vblank_handler, | ||
379 | evctx.page_flip_handler = HWCDisplay::page_flip_handler, | ||
380 | }; | ||
381 | |||
382 | while (true) { | ||
383 | int ret = poll(&pfds, 1, 60000); | ||
384 | if (ret < 0) { | ||
385 | ALOGE("Event poll error %d", errno); | ||
386 | break; | ||
387 | } else if (ret == 0) { | ||
388 | ALOGI("Event poll timeout"); | ||
389 | continue; | ||
390 | } | ||
391 | if (pfds.revents & POLLIN) | ||
392 | drmHandleEvent(pfds.fd, &evctx); | ||
393 | } | ||
394 | |||
395 | ALOGE("DRM event polling thread exiting\n"); | ||
396 | } | ||
397 | |||
398 | static void adjust_drm_plane_to_layer(hwc_layer_1_t* layer, int zorder, drm_plane_props_t* plane) | ||
399 | { | ||
400 | if (!layer || !plane) { | ||
401 | ALOGE("Bad layer or plane"); | ||
402 | return; | ||
403 | } | ||
404 | |||
405 | /* display position */ | ||
406 | plane->crtc_x = layer->displayFrame.left; | ||
407 | plane->crtc_y = layer->displayFrame.top; | ||
408 | plane->crtc_w = WIDTH(layer->displayFrame); | ||
409 | plane->crtc_h = HEIGHT(layer->displayFrame); | ||
410 | |||
411 | /* crop */ | ||
412 | plane->src_x = layer->sourceCrop.left; | ||
413 | plane->src_y = layer->sourceCrop.top; | ||
414 | plane->src_w = WIDTH(layer->sourceCrop); | ||
415 | plane->src_h = HEIGHT(layer->sourceCrop); | ||
416 | |||
417 | plane->zorder = zorder; | ||
418 | plane->layer = layer; | ||
419 | |||
420 | if (layer->blending == HWC_BLENDING_PREMULT) | ||
421 | plane->pre_mult_alpha = 1; | ||
422 | else | ||
423 | plane->pre_mult_alpha = 0; | ||
424 | } | ||
425 | |||
426 | static int hwc_prepare_for_display(omap_hwc_device_t* hwc_dev, int disp, hwc_display_contents_1_t* content) | ||
427 | { | ||
428 | if (!is_valid_display(hwc_dev, disp)) | ||
429 | return -ENODEV; | ||
430 | |||
431 | HWCDisplay* display = hwc_dev->displays[disp]; | ||
432 | |||
433 | if (display->is_dummy) { | ||
434 | for (size_t i = 0; i < content->numHwLayers - 1; i++) { | ||
435 | hwc_layer_1_t* layer = &content->hwLayers[i]; | ||
436 | layer->compositionType = HWC_OVERLAY; | ||
437 | } | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | /* Set the FB_TARGET layer */ | ||
442 | adjust_drm_plane_to_layer(&content->hwLayers[content->numHwLayers - 1], 0, &display->planeProps[disp]); | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static int hwc_prepare(struct hwc_composer_device_1* dev, size_t numDisplays, hwc_display_contents_1_t** displays) | ||
448 | { | ||
449 | atrace_begin(ATRACE_TAG_HAL, "am57xx_hwc_prepare"); | ||
450 | if (!numDisplays || !displays) | ||
451 | return 0; | ||
452 | |||
453 | omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev; | ||
454 | std::unique_lock<std::mutex> lock(hwc_dev->mutex); | ||
455 | |||
456 | int err = 0; | ||
457 | |||
458 | for (size_t i = 0; i < numDisplays; i++) { | ||
459 | hwc_display_contents_1_t* contents = displays[i]; | ||
460 | |||
461 | if (!contents) | ||
462 | continue; | ||
463 | |||
464 | if (contents->numHwLayers == 0) { | ||
465 | ALOGW("Prepare given no content for display %d", i); | ||
466 | continue; | ||
467 | } | ||
468 | |||
469 | int disp_err = hwc_prepare_for_display(hwc_dev, i, contents); | ||
470 | if (!err && disp_err) | ||
471 | err = disp_err; | ||
472 | } | ||
473 | |||
474 | atrace_end(ATRACE_TAG_HAL); | ||
475 | return err; | ||
476 | } | ||
477 | |||
478 | static int hwc_set_for_display(omap_hwc_device_t* hwc_dev, int disp, hwc_display_contents_1_t* content) | ||
479 | { | ||
480 | if (!is_valid_display(hwc_dev, disp)) | ||
481 | return -ENODEV; | ||
482 | |||
483 | HWCDisplay* display = hwc_dev->displays[disp]; | ||
484 | drm_plane_props_t* planeProp = &display->planeProps[disp]; | ||
485 | |||
486 | int err = 0; | ||
487 | |||
488 | /* | ||
489 | * clear release and retire fence fd's here in case we do | ||
490 | * not set them in update_display() | ||
491 | */ | ||
492 | for (size_t i = 0; i < content->numHwLayers; i++) { | ||
493 | hwc_layer_1_t* layer = &content->hwLayers[i]; | ||
494 | layer->releaseFenceFd = -1; | ||
495 | } | ||
496 | content->retireFenceFd = -1; | ||
497 | |||
498 | if (!display->is_dummy) { | ||
499 | err = display->update_display(planeProp); | ||
500 | if (err) | ||
501 | ALOGE("Failed to update display %d\n", disp); | ||
502 | } | ||
503 | |||
504 | /* clear any remaining acquire fences */ | ||
505 | for (size_t i = 0; i < content->numHwLayers; i++) { | ||
506 | hwc_layer_1_t* layer = &content->hwLayers[i]; | ||
507 | if (layer->acquireFenceFd >= 0) { | ||
508 | close(layer->acquireFenceFd); | ||
509 | layer->acquireFenceFd = -1; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | return err; | ||
514 | } | ||
515 | |||
516 | static int hwc_set(struct hwc_composer_device_1* dev, size_t numDisplays, hwc_display_contents_1_t** displays) | ||
517 | { | ||
518 | atrace_begin(ATRACE_TAG_HAL, "am57xx_hwc_set"); | ||
519 | if (!numDisplays || !displays) | ||
520 | return 0; | ||
521 | |||
522 | omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev; | ||
523 | std::unique_lock<std::mutex> lock(hwc_dev->mutex); | ||
524 | |||
525 | int err = 0; | ||
526 | |||
527 | for (size_t i = 0; i < numDisplays; i++) { | ||
528 | hwc_display_contents_1_t* contents = displays[i]; | ||
529 | |||
530 | if (!contents) | ||
531 | continue; | ||
532 | |||
533 | if (contents->numHwLayers == 0) { | ||
534 | ALOGE("Set given no content for display %d", i); | ||
535 | continue; | ||
536 | } | ||
537 | |||
538 | int disp_err = hwc_set_for_display(hwc_dev, i, contents); | ||
539 | if (!err && disp_err) | ||
540 | err = disp_err; | ||
541 | } | ||
542 | |||
543 | atrace_end(ATRACE_TAG_HAL); | ||
544 | return err; | ||
545 | } | ||
546 | |||
547 | static int hwc_eventControl(struct hwc_composer_device_1* dev, int disp, int event, int enabled) | ||
548 | { | ||
549 | omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev; | ||
550 | std::unique_lock<std::mutex> lock(hwc_dev->mutex); | ||
551 | |||
552 | if (!is_valid_display(hwc_dev, disp)) | ||
553 | return -EINVAL; | ||
554 | |||
555 | switch (event) { | ||
556 | case HWC_EVENT_VSYNC: | ||
557 | // FIXME: This is a hack | ||
558 | hwc_dev->displays[disp]->cb_procs = hwc_dev->cb_procs; | ||
559 | |||
560 | ALOGD("%s vsync for display %d", enabled ? "Enabling" : "Disabling", disp); | ||
561 | return hwc_dev->displays[disp]->set_vsync_state(enabled); | ||
562 | |||
563 | default: | ||
564 | return -EINVAL; | ||
565 | } | ||
566 | |||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | static int hwc_blank(struct hwc_composer_device_1* dev, int disp, int blank) | ||
571 | { | ||
572 | omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev; | ||
573 | std::unique_lock<std::mutex> lock(hwc_dev->mutex); | ||
574 | |||
575 | ALOGD("%s display %d", blank ? "Blanking" : "Unblanking", disp); | ||
576 | |||
577 | if (!is_valid_display(hwc_dev, disp)) | ||
578 | return -EINVAL; | ||
579 | |||
580 | hwc_dev->displays[disp]->blank(blank); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static int hwc_query(struct hwc_composer_device_1* dev, int what, int* value) | ||
586 | { | ||
587 | omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev; | ||
588 | std::unique_lock<std::mutex> lock(hwc_dev->mutex); | ||
589 | |||
590 | switch (what) { | ||
591 | case HWC_BACKGROUND_LAYER_SUPPORTED: | ||
592 | // we don't support the background layer yet | ||
593 | value[0] = 0; | ||
594 | break; | ||
595 | case HWC_VSYNC_PERIOD: | ||
596 | ALOGW("Query for deprecated vsync value, returning 60Hz"); | ||
597 | *value = 1000 * 1000 * 1000 / 60; | ||
598 | break; | ||
599 | case HWC_DISPLAY_TYPES_SUPPORTED: | ||
600 | *value = HWC_DISPLAY_PRIMARY_BIT | HWC_DISPLAY_EXTERNAL_BIT; | ||
601 | break; | ||
602 | default: | ||
603 | // unsupported query | ||
604 | return -EINVAL; | ||
605 | } | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | static void hwc_registerProcs(struct hwc_composer_device_1* dev, hwc_procs_t const* procs) | ||
611 | { | ||
612 | omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev; | ||
613 | std::unique_lock<std::mutex> lock(hwc_dev->mutex); | ||
614 | |||
615 | hwc_dev->cb_procs = (typeof(hwc_dev->cb_procs))procs; | ||
616 | |||
617 | /* now that cb_procs->hotplug is valid */ | ||
618 | try { | ||
619 | hwc_dev->hdmi_thread = new std::thread(hwc_hdmi_thread, hwc_dev); | ||
620 | } catch (...) { | ||
621 | ALOGE("Failed to create HDMI listening thread (%s)", strerror(errno)); | ||
622 | } | ||
623 | } | ||
624 | |||
625 | static int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp, uint32_t* configs, size_t* numConfigs) | ||
626 | { | ||
627 | omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev; | ||
628 | std::unique_lock<std::mutex> lock(hwc_dev->mutex); | ||
629 | |||
630 | if (!is_valid_display(hwc_dev, disp)) | ||
631 | return -EINVAL; | ||
632 | |||
633 | HWCDisplay* display = hwc_dev->displays[disp]; | ||
634 | |||
635 | return display->get_display_configs(configs, numConfigs); | ||
636 | } | ||
637 | |||
638 | static int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp, uint32_t config, const uint32_t* attributes, int32_t* values) | ||
639 | { | ||
640 | omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev; | ||
641 | std::unique_lock<std::mutex> lock(hwc_dev->mutex); | ||
642 | |||
643 | if (!is_valid_display(hwc_dev, disp)) | ||
644 | return -EINVAL; | ||
645 | |||
646 | HWCDisplay* display = hwc_dev->displays[disp]; | ||
647 | |||
648 | return display->get_display_attributes(config, attributes, values); | ||
649 | } | ||
650 | |||
651 | static int hwc_device_close(hw_device_t* device) | ||
652 | { | ||
653 | omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)device; | ||
654 | |||
655 | if (hwc_dev) { | ||
656 | if (hwc_dev->event_thread) | ||
657 | delete hwc_dev->event_thread; | ||
658 | |||
659 | for (size_t i = 0; i < MAX_DISPLAYS; i++) | ||
660 | delete hwc_dev->displays[i]; | ||
661 | |||
662 | delete hwc_dev; | ||
663 | } | ||
664 | |||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | static int hwc_device_open(const hw_module_t* module, const char* name, hw_device_t** device) | ||
669 | { | ||
670 | if (strcmp(name, HWC_HARDWARE_COMPOSER)) | ||
671 | return -EINVAL; | ||
672 | |||
673 | omap_hwc_device_t* hwc_dev = new omap_hwc_device_t; | ||
674 | memset(hwc_dev, 0, sizeof(*hwc_dev)); | ||
675 | |||
676 | /* Open DRM device */ | ||
677 | hwc_dev->card = new kms::Card(); | ||
678 | |||
679 | /* Find primary and external connectors */ | ||
680 | get_connectors(hwc_dev); | ||
681 | |||
682 | int ret = init_primary_display(hwc_dev); | ||
683 | if (ret) { | ||
684 | ALOGE("Could not initialize primary display"); | ||
685 | return -1; | ||
686 | } | ||
687 | |||
688 | hwc_dev->event_thread = new std::thread(hwc_drm_event_thread, hwc_dev); | ||
689 | |||
690 | hwc_dev->device.common.tag = HARDWARE_DEVICE_TAG; | ||
691 | hwc_dev->device.common.version = HWC_DEVICE_API_VERSION_1_1; | ||
692 | hwc_dev->device.common.module = (hw_module_t*)module; | ||
693 | hwc_dev->device.common.close = hwc_device_close; | ||
694 | hwc_dev->device.prepare = hwc_prepare; | ||
695 | hwc_dev->device.set = hwc_set; | ||
696 | hwc_dev->device.eventControl = hwc_eventControl; | ||
697 | hwc_dev->device.blank = hwc_blank; | ||
698 | hwc_dev->device.query = hwc_query; | ||
699 | hwc_dev->device.registerProcs = hwc_registerProcs; | ||
700 | hwc_dev->device.getDisplayConfigs = hwc_getDisplayConfigs; | ||
701 | hwc_dev->device.getDisplayAttributes = hwc_getDisplayAttributes; | ||
702 | |||
703 | *device = &hwc_dev->device.common; | ||
704 | |||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | static struct hw_module_methods_t module_methods = { | ||
709 | .open = hwc_device_open, | ||
710 | }; | ||
711 | |||
712 | omap_hwc_module_t HAL_MODULE_INFO_SYM = { | ||
713 | .base = { | ||
714 | .common = { | ||
715 | .tag = HARDWARE_MODULE_TAG, | ||
716 | .module_api_version = HWC_MODULE_API_VERSION_0_1, | ||
717 | .hal_api_version = HARDWARE_HAL_API_VERSION, | ||
718 | .id = HWC_HARDWARE_MODULE_ID, | ||
719 | .name = "AM57xx Hardware Composer HAL", | ||
720 | .author = "Texas Instruments", | ||
721 | .methods = &module_methods, | ||
722 | }, | ||
723 | }, | ||
724 | }; | ||
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 @@ | |||
1 | /* | ||
2 | * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/ | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #ifndef HWC_DEV_H | ||
18 | #define HWC_DEV_H | ||
19 | |||
20 | #include <mutex> | ||
21 | #include <thread> | ||
22 | |||
23 | #include <cstdbool> | ||
24 | #include <cstdint> | ||
25 | |||
26 | #include <hardware/hwcomposer.h> | ||
27 | #include <kms++/kms++.h> | ||
28 | |||
29 | #include "display.h" | ||
30 | |||
31 | typedef struct omap_hwc_module { | ||
32 | hwc_module_t base; | ||
33 | |||
34 | } omap_hwc_module_t; | ||
35 | |||
36 | typedef struct omap_hwc_device { | ||
37 | /* static data */ | ||
38 | hwc_composer_device_1_t device; | ||
39 | |||
40 | std::mutex mutex; | ||
41 | |||
42 | std::thread* hdmi_thread; | ||
43 | std::thread* event_thread; | ||
44 | |||
45 | kms::Card* card; | ||
46 | |||
47 | HWCDisplay* displays[MAX_DISPLAYS]; | ||
48 | |||
49 | kms::Connector* primaryConector; | ||
50 | kms::Connector* externalConector; | ||
51 | |||
52 | drmEventContext evctx; | ||
53 | |||
54 | const hwc_procs_t* cb_procs; | ||
55 | } omap_hwc_device_t; | ||
56 | |||
57 | #endif /* HWC_DEV_H */ | ||