|
1 /* Copyright 2013 Mozilla Foundation and Mozilla contributors |
|
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 |
|
16 #include "GonkDisplayICS.h" |
|
17 #include <ui/FramebufferNativeWindow.h> |
|
18 |
|
19 #include <hardware/hardware.h> |
|
20 #include <hardware/gralloc.h> |
|
21 #include <hardware/hwcomposer.h> |
|
22 #include <hardware_legacy/power.h> |
|
23 #include <cutils/log.h> |
|
24 #include <fcntl.h> |
|
25 |
|
26 #include "mozilla/FileUtils.h" |
|
27 #include "mozilla/NullPtr.h" |
|
28 #include "mozilla/FileUtils.h" |
|
29 |
|
30 #include "BootAnimation.h" |
|
31 |
|
32 using namespace android; |
|
33 |
|
34 |
|
35 namespace { |
|
36 static const char* kSleepFile = "/sys/power/wait_for_fb_sleep"; |
|
37 static const char* kWakeFile = "/sys/power/wait_for_fb_wake"; |
|
38 static mozilla::GonkDisplay::OnEnabledCallbackType sEnabledCallback; |
|
39 static pthread_t sFramebufferWatchThread; |
|
40 |
|
41 static void * |
|
42 frameBufferWatcher(void *) |
|
43 { |
|
44 int len = 0; |
|
45 char buf; |
|
46 |
|
47 while (true) { |
|
48 // Cannot use epoll here because kSleepFile and kWakeFile are |
|
49 // always ready to read and blocking. |
|
50 { |
|
51 mozilla::ScopedClose fd(open(kSleepFile, O_RDONLY, 0)); |
|
52 do { |
|
53 len = read(fd.get(), &buf, 1); |
|
54 } while (len < 0 && errno == EINTR); |
|
55 NS_WARN_IF_FALSE(len >= 0, "WAIT_FOR_FB_SLEEP failed"); |
|
56 } |
|
57 sEnabledCallback(false); |
|
58 |
|
59 { |
|
60 mozilla::ScopedClose fd(open(kWakeFile, O_RDONLY, 0)); |
|
61 do { |
|
62 len = read(fd.get(), &buf, 1); |
|
63 } while (len < 0 && errno == EINTR); |
|
64 NS_WARN_IF_FALSE(len >= 0, "WAIT_FOR_FB_WAKE failed"); |
|
65 } |
|
66 sEnabledCallback(true); |
|
67 } |
|
68 |
|
69 return nullptr; |
|
70 } |
|
71 |
|
72 } // anonymous namespace |
|
73 |
|
74 |
|
75 namespace mozilla { |
|
76 |
|
77 static GonkDisplayICS* sGonkDisplay = nullptr; |
|
78 |
|
79 static int |
|
80 FramebufferNativeWindowCancelBufferNoop(ANativeWindow* aWindow, |
|
81 android_native_buffer_t* aBuffer) |
|
82 { |
|
83 return 0; |
|
84 } |
|
85 |
|
86 GonkDisplayICS::GonkDisplayICS() |
|
87 : mModule(nullptr) |
|
88 , mHwc(nullptr) |
|
89 { |
|
90 // Some gralloc HALs need this in order to open the |
|
91 // framebuffer device after we restart with the screen off. |
|
92 // |
|
93 // this *must* run BEFORE allocating the |
|
94 // FramebufferNativeWindow. |
|
95 set_screen_state(1); |
|
96 |
|
97 // For some devices, it takes a while for the framebuffer to become |
|
98 // usable. So we wait until the framebuffer has woken up before we |
|
99 // try to open it. |
|
100 { |
|
101 char buf; |
|
102 int len = 0; |
|
103 ScopedClose fd(open("/sys/power/wait_for_fb_wake", O_RDONLY, 0)); |
|
104 do { |
|
105 len = read(fd.get(), &buf, 1); |
|
106 } while (len < 0 && errno == EINTR); |
|
107 if (len < 0) { |
|
108 LOGE("BootAnimation: wait_for_fb_sleep failed errno: %d", errno); |
|
109 } |
|
110 } |
|
111 |
|
112 mFBSurface = new FramebufferNativeWindow(); |
|
113 |
|
114 // ICS FramebufferNativeWindow doesn't set the |cancelBuffer| |
|
115 // function pointer. |
|
116 // It will crash when deleting the EGL window surface. |
|
117 if (!mFBSurface->cancelBuffer) { |
|
118 mFBSurface->cancelBuffer = FramebufferNativeWindowCancelBufferNoop; |
|
119 } |
|
120 |
|
121 int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule); |
|
122 LOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID); |
|
123 if (!err) { |
|
124 err = hwc_open(mModule, &mHwc); |
|
125 LOGE_IF(err, "%s device failed to initialize (%s)", |
|
126 HWC_HARDWARE_COMPOSER, strerror(-err)); |
|
127 } |
|
128 |
|
129 xdpi = mFBSurface->xdpi; |
|
130 |
|
131 const framebuffer_device_t *fbdev = mFBSurface->getDevice(); |
|
132 surfaceformat = fbdev->format; |
|
133 |
|
134 StartBootAnimation(); |
|
135 } |
|
136 |
|
137 GonkDisplayICS::~GonkDisplayICS() |
|
138 { |
|
139 if (mHwc) |
|
140 hwc_close(mHwc); |
|
141 } |
|
142 |
|
143 ANativeWindow* |
|
144 GonkDisplayICS::GetNativeWindow() |
|
145 { |
|
146 StopBootAnimation(); |
|
147 return static_cast<ANativeWindow *>(mFBSurface.get()); |
|
148 } |
|
149 |
|
150 void |
|
151 GonkDisplayICS::SetEnabled(bool enabled) |
|
152 { |
|
153 set_screen_state(enabled); |
|
154 } |
|
155 |
|
156 void |
|
157 GonkDisplayICS::OnEnabled(OnEnabledCallbackType callback) |
|
158 { |
|
159 if (sEnabledCallback) |
|
160 return; |
|
161 sEnabledCallback = callback; |
|
162 |
|
163 // Watching screen on/off state by using a pthread |
|
164 // which implicitly calls exit() when the main thread ends |
|
165 if (pthread_create(&sFramebufferWatchThread, NULL, frameBufferWatcher, NULL)) { |
|
166 NS_RUNTIMEABORT("Failed to create framebufferWatcherThread, aborting..."); |
|
167 } |
|
168 } |
|
169 |
|
170 |
|
171 void* |
|
172 GonkDisplayICS::GetHWCDevice() |
|
173 { |
|
174 return mHwc; |
|
175 } |
|
176 |
|
177 void* |
|
178 GonkDisplayICS::GetFBSurface() |
|
179 { |
|
180 return mFBSurface.get(); |
|
181 } |
|
182 |
|
183 bool |
|
184 GonkDisplayICS::SwapBuffers(EGLDisplay dpy, EGLSurface sur) |
|
185 { |
|
186 // Should be called when composition rendering is complete for a frame. |
|
187 // Only HWC v1.0 needs this call. ICS gonk always needs the call. |
|
188 mFBSurface->compositionComplete(); |
|
189 |
|
190 if (!mHwc) |
|
191 return eglSwapBuffers(dpy, sur); |
|
192 |
|
193 mHwc->prepare(mHwc, nullptr); |
|
194 return !mHwc->set(mHwc, dpy, sur, 0); |
|
195 } |
|
196 |
|
197 ANativeWindowBuffer* |
|
198 GonkDisplayICS::DequeueBuffer() |
|
199 { |
|
200 ANativeWindow *window = static_cast<ANativeWindow *>(mFBSurface.get()); |
|
201 ANativeWindowBuffer *buf = nullptr; |
|
202 window->dequeueBuffer(window, &buf); |
|
203 return buf; |
|
204 } |
|
205 |
|
206 bool |
|
207 GonkDisplayICS::QueueBuffer(ANativeWindowBuffer *buf) |
|
208 { |
|
209 ANativeWindow *window = static_cast<ANativeWindow *>(mFBSurface.get()); |
|
210 return !window->queueBuffer(window, buf); |
|
211 } |
|
212 |
|
213 void |
|
214 GonkDisplayICS::UpdateFBSurface(EGLDisplay dpy, EGLSurface sur) |
|
215 { |
|
216 eglSwapBuffers(dpy, sur); |
|
217 } |
|
218 |
|
219 void |
|
220 GonkDisplayICS::SetFBReleaseFd(int fd) |
|
221 { |
|
222 } |
|
223 |
|
224 __attribute__ ((visibility ("default"))) |
|
225 GonkDisplay* |
|
226 GetGonkDisplay() |
|
227 { |
|
228 if (!sGonkDisplay) |
|
229 sGonkDisplay = new GonkDisplayICS(); |
|
230 return sGonkDisplay; |
|
231 } |
|
232 |
|
233 } // namespace mozilla |