|
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 "GonkDisplayJB.h" |
|
17 #if ANDROID_VERSION == 17 |
|
18 #include <gui/SurfaceTextureClient.h> |
|
19 #else |
|
20 #include <gui/Surface.h> |
|
21 #include <gui/GraphicBufferAlloc.h> |
|
22 #endif |
|
23 |
|
24 #include <hardware/hardware.h> |
|
25 #include <hardware/hwcomposer.h> |
|
26 #include <hardware/power.h> |
|
27 #include <suspend/autosuspend.h> |
|
28 |
|
29 #if ANDROID_VERSION == 17 |
|
30 #include "GraphicBufferAlloc.h" |
|
31 #endif |
|
32 #include "BootAnimation.h" |
|
33 |
|
34 using namespace android; |
|
35 |
|
36 namespace mozilla { |
|
37 |
|
38 static GonkDisplayJB* sGonkDisplay = nullptr; |
|
39 |
|
40 GonkDisplayJB::GonkDisplayJB() |
|
41 : mList(nullptr) |
|
42 , mModule(nullptr) |
|
43 , mFBModule(nullptr) |
|
44 , mHwc(nullptr) |
|
45 , mFBDevice(nullptr) |
|
46 , mEnabledCallback(nullptr) |
|
47 , mPowerModule(nullptr) |
|
48 { |
|
49 int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mFBModule); |
|
50 ALOGW_IF(err, "%s module not found", GRALLOC_HARDWARE_MODULE_ID); |
|
51 if (!err) { |
|
52 err = framebuffer_open(mFBModule, &mFBDevice); |
|
53 ALOGW_IF(err, "could not open framebuffer"); |
|
54 } |
|
55 |
|
56 if (!err && mFBDevice) { |
|
57 mWidth = mFBDevice->width; |
|
58 mHeight = mFBDevice->height; |
|
59 xdpi = mFBDevice->xdpi; |
|
60 /* The emulator actually reports RGBA_8888, but EGL doesn't return |
|
61 * any matching configuration. We force RGBX here to fix it. */ |
|
62 surfaceformat = HAL_PIXEL_FORMAT_RGBX_8888; |
|
63 } |
|
64 |
|
65 err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule); |
|
66 ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID); |
|
67 if (!err) { |
|
68 err = hwc_open_1(mModule, &mHwc); |
|
69 ALOGE_IF(err, "%s device failed to initialize (%s)", |
|
70 HWC_HARDWARE_COMPOSER, strerror(-err)); |
|
71 } |
|
72 |
|
73 /* Fallback on the FB rendering path instead of trying to support HWC 1.0 */ |
|
74 if (!err && mHwc->common.version == HWC_DEVICE_API_VERSION_1_0) { |
|
75 hwc_close_1(mHwc); |
|
76 mHwc = nullptr; |
|
77 } |
|
78 |
|
79 if (!err && mHwc) { |
|
80 if (mFBDevice) { |
|
81 framebuffer_close(mFBDevice); |
|
82 mFBDevice = nullptr; |
|
83 } |
|
84 |
|
85 int32_t values[3]; |
|
86 const uint32_t attrs[] = { |
|
87 HWC_DISPLAY_WIDTH, |
|
88 HWC_DISPLAY_HEIGHT, |
|
89 HWC_DISPLAY_DPI_X, |
|
90 HWC_DISPLAY_NO_ATTRIBUTE |
|
91 }; |
|
92 mHwc->getDisplayAttributes(mHwc, 0, 0, attrs, values); |
|
93 |
|
94 mWidth = values[0]; |
|
95 mHeight = values[1]; |
|
96 xdpi = values[2] / 1000.0f; |
|
97 surfaceformat = HAL_PIXEL_FORMAT_RGBA_8888; |
|
98 } |
|
99 |
|
100 err = hw_get_module(POWER_HARDWARE_MODULE_ID, |
|
101 (hw_module_t const**)&mPowerModule); |
|
102 if (!err) |
|
103 mPowerModule->init(mPowerModule); |
|
104 ALOGW_IF(err, "Couldn't load %s module (%s)", POWER_HARDWARE_MODULE_ID, strerror(-err)); |
|
105 |
|
106 mAlloc = new GraphicBufferAlloc(); |
|
107 |
|
108 status_t error; |
|
109 uint32_t usage = GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER; |
|
110 mBootAnimBuffer = mAlloc->createGraphicBuffer(mWidth, mHeight, surfaceformat, usage, &error); |
|
111 if (error != NO_ERROR || !mBootAnimBuffer.get()) { |
|
112 ALOGI("Trying to create BRGA format framebuffer"); |
|
113 surfaceformat = HAL_PIXEL_FORMAT_BGRA_8888; |
|
114 mBootAnimBuffer = mAlloc->createGraphicBuffer(mWidth, mHeight, surfaceformat, usage, &error); |
|
115 } |
|
116 |
|
117 #if ANDROID_VERSION >= 19 |
|
118 sp<BufferQueue> bq = new BufferQueue(mAlloc); |
|
119 #else |
|
120 sp<BufferQueue> bq = new BufferQueue(true, mAlloc); |
|
121 #endif |
|
122 mFBSurface = new FramebufferSurface(0, mWidth, mHeight, surfaceformat, bq); |
|
123 |
|
124 #if ANDROID_VERSION == 17 |
|
125 sp<SurfaceTextureClient> stc = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >(mFBSurface->getBufferQueue())); |
|
126 #else |
|
127 sp<Surface> stc = new Surface(static_cast<sp<IGraphicBufferProducer> >(bq)); |
|
128 #endif |
|
129 mSTClient = stc; |
|
130 |
|
131 mList = (hwc_display_contents_1_t *)malloc(sizeof(*mList) + (sizeof(hwc_layer_1_t)*2)); |
|
132 if (mHwc) |
|
133 mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, 0); |
|
134 |
|
135 if (error == NO_ERROR && mBootAnimBuffer.get()) { |
|
136 ALOGI("Starting bootanimation with (%d) format framebuffer", surfaceformat); |
|
137 StartBootAnimation(); |
|
138 } else |
|
139 ALOGW("Couldn't show bootanimation (%s)", strerror(-error)); |
|
140 } |
|
141 |
|
142 GonkDisplayJB::~GonkDisplayJB() |
|
143 { |
|
144 if (mHwc) |
|
145 hwc_close_1(mHwc); |
|
146 if (mFBDevice) |
|
147 framebuffer_close(mFBDevice); |
|
148 free(mList); |
|
149 } |
|
150 |
|
151 ANativeWindow* |
|
152 GonkDisplayJB::GetNativeWindow() |
|
153 { |
|
154 return mSTClient.get(); |
|
155 } |
|
156 |
|
157 void |
|
158 GonkDisplayJB::SetEnabled(bool enabled) |
|
159 { |
|
160 if (enabled) { |
|
161 autosuspend_disable(); |
|
162 mPowerModule->setInteractive(mPowerModule, true); |
|
163 } |
|
164 |
|
165 if (mHwc) |
|
166 mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, !enabled); |
|
167 else if (mFBDevice->enableScreen) |
|
168 mFBDevice->enableScreen(mFBDevice, enabled); |
|
169 |
|
170 if (mEnabledCallback) |
|
171 mEnabledCallback(enabled); |
|
172 |
|
173 if (!enabled) { |
|
174 autosuspend_enable(); |
|
175 mPowerModule->setInteractive(mPowerModule, false); |
|
176 } |
|
177 } |
|
178 |
|
179 void |
|
180 GonkDisplayJB::OnEnabled(OnEnabledCallbackType callback) |
|
181 { |
|
182 mEnabledCallback = callback; |
|
183 } |
|
184 |
|
185 void* |
|
186 GonkDisplayJB::GetHWCDevice() |
|
187 { |
|
188 return mHwc; |
|
189 } |
|
190 |
|
191 void* |
|
192 GonkDisplayJB::GetFBSurface() |
|
193 { |
|
194 return mFBSurface.get(); |
|
195 } |
|
196 |
|
197 bool |
|
198 GonkDisplayJB::SwapBuffers(EGLDisplay dpy, EGLSurface sur) |
|
199 { |
|
200 StopBootAnimation(); |
|
201 mBootAnimBuffer = nullptr; |
|
202 |
|
203 // Should be called when composition rendering is complete for a frame. |
|
204 // Only HWC v1.0 needs this call. |
|
205 // HWC > v1.0 case, do not call compositionComplete(). |
|
206 // mFBDevice is present only when HWC is v1.0. |
|
207 if (mFBDevice && mFBDevice->compositionComplete) { |
|
208 mFBDevice->compositionComplete(mFBDevice); |
|
209 } |
|
210 |
|
211 #if ANDROID_VERSION == 17 |
|
212 mList->dpy = dpy; |
|
213 mList->sur = sur; |
|
214 #else |
|
215 mList->outbuf = nullptr; |
|
216 mList->outbufAcquireFenceFd = -1; |
|
217 #endif |
|
218 eglSwapBuffers(dpy, sur); |
|
219 return Post(mFBSurface->lastHandle, mFBSurface->GetPrevFBAcquireFd()); |
|
220 } |
|
221 |
|
222 bool |
|
223 GonkDisplayJB::Post(buffer_handle_t buf, int fence) |
|
224 { |
|
225 if (!mHwc) { |
|
226 if (fence >= 0) |
|
227 close(fence); |
|
228 return !mFBDevice->post(mFBDevice, buf); |
|
229 } |
|
230 |
|
231 hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = {NULL}; |
|
232 const hwc_rect_t r = { 0, 0, mWidth, mHeight }; |
|
233 displays[HWC_DISPLAY_PRIMARY] = mList; |
|
234 mList->retireFenceFd = -1; |
|
235 mList->numHwLayers = 2; |
|
236 mList->flags = HWC_GEOMETRY_CHANGED; |
|
237 mList->hwLayers[0].compositionType = HWC_FRAMEBUFFER; |
|
238 mList->hwLayers[0].hints = 0; |
|
239 /* Skip this layer so the hwc module doesn't complain about null handles */ |
|
240 mList->hwLayers[0].flags = HWC_SKIP_LAYER; |
|
241 mList->hwLayers[0].backgroundColor = {0}; |
|
242 mList->hwLayers[0].acquireFenceFd = -1; |
|
243 mList->hwLayers[0].releaseFenceFd = -1; |
|
244 /* hwc module checks displayFrame even though it shouldn't */ |
|
245 mList->hwLayers[0].displayFrame = r; |
|
246 mList->hwLayers[1].compositionType = HWC_FRAMEBUFFER_TARGET; |
|
247 mList->hwLayers[1].hints = 0; |
|
248 mList->hwLayers[1].flags = 0; |
|
249 mList->hwLayers[1].handle = buf; |
|
250 mList->hwLayers[1].transform = 0; |
|
251 mList->hwLayers[1].blending = HWC_BLENDING_PREMULT; |
|
252 #if ANDROID_VERSION >= 19 |
|
253 if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_3) { |
|
254 mList->hwLayers[1].sourceCropf.left = 0; |
|
255 mList->hwLayers[1].sourceCropf.top = 0; |
|
256 mList->hwLayers[1].sourceCropf.right = mWidth; |
|
257 mList->hwLayers[1].sourceCropf.bottom = mHeight; |
|
258 } else { |
|
259 mList->hwLayers[1].sourceCrop = r; |
|
260 } |
|
261 #else |
|
262 mList->hwLayers[1].sourceCrop = r; |
|
263 #endif |
|
264 mList->hwLayers[1].displayFrame = r; |
|
265 mList->hwLayers[1].visibleRegionScreen.numRects = 1; |
|
266 mList->hwLayers[1].visibleRegionScreen.rects = &mList->hwLayers[1].displayFrame; |
|
267 mList->hwLayers[1].acquireFenceFd = fence; |
|
268 mList->hwLayers[1].releaseFenceFd = -1; |
|
269 #if ANDROID_VERSION == 18 |
|
270 mList->hwLayers[1].planeAlpha = 0xFF; |
|
271 #endif |
|
272 mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays); |
|
273 int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays); |
|
274 mFBSurface->setReleaseFenceFd(mList->hwLayers[1].releaseFenceFd); |
|
275 if (mList->retireFenceFd >= 0) |
|
276 close(mList->retireFenceFd); |
|
277 return !err; |
|
278 } |
|
279 |
|
280 ANativeWindowBuffer* |
|
281 GonkDisplayJB::DequeueBuffer() |
|
282 { |
|
283 return static_cast<ANativeWindowBuffer*>(mBootAnimBuffer.get()); |
|
284 } |
|
285 |
|
286 bool |
|
287 GonkDisplayJB::QueueBuffer(ANativeWindowBuffer* buf) |
|
288 { |
|
289 bool success = Post(buf->handle, -1); |
|
290 return success; |
|
291 } |
|
292 |
|
293 void |
|
294 GonkDisplayJB::UpdateFBSurface(EGLDisplay dpy, EGLSurface sur) |
|
295 { |
|
296 StopBootAnimation(); |
|
297 mBootAnimBuffer = nullptr; |
|
298 eglSwapBuffers(dpy, sur); |
|
299 } |
|
300 |
|
301 void |
|
302 GonkDisplayJB::SetFBReleaseFd(int fd) |
|
303 { |
|
304 mFBSurface->setReleaseFenceFd(fd); |
|
305 } |
|
306 |
|
307 int |
|
308 GonkDisplayJB::GetPrevFBAcquireFd() |
|
309 { |
|
310 return mFBSurface->GetPrevFBAcquireFd(); |
|
311 } |
|
312 |
|
313 __attribute__ ((visibility ("default"))) |
|
314 GonkDisplay* |
|
315 GetGonkDisplay() |
|
316 { |
|
317 if (!sGonkDisplay) |
|
318 sGonkDisplay = new GonkDisplayJB(); |
|
319 return sGonkDisplay; |
|
320 } |
|
321 |
|
322 } // namespace mozilla |