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 >= 19
30 #include "VirtualDisplaySurface.h"
31 #endif
32 #include "FramebufferSurface.h"
33 #if ANDROID_VERSION == 17
34 #include "GraphicBufferAlloc.h"
35 #endif
36 #include "mozilla/Assertions.h"
37
38 #define DEFAULT_XDPI 75.0
39
40 using namespace android;
41
42 namespace mozilla {
43
44 static GonkDisplayJB* sGonkDisplay = nullptr;
45
GonkDisplayJB()46 GonkDisplayJB::GonkDisplayJB()
47 : mModule(nullptr)
48 , mFBModule(nullptr)
49 , mHwc(nullptr)
50 , mFBDevice(nullptr)
51 , mPowerModule(nullptr)
52 , mList(nullptr)
53 , mWidth(0)
54 , mHeight(0)
55 , mEnabledCallback(nullptr)
56 {
57 int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mFBModule);
58 ALOGW_IF(err, "%s module not found", GRALLOC_HARDWARE_MODULE_ID);
59 if (!err) {
60 err = framebuffer_open(mFBModule, &mFBDevice);
61 ALOGW_IF(err, "could not open framebuffer");
62 }
63
64 if (!err && mFBDevice) {
65 mWidth = mFBDevice->width;
66 mHeight = mFBDevice->height;
67 xdpi = mFBDevice->xdpi;
68 /* The emulator actually reports RGBA_8888, but EGL doesn't return
69 * any matching configuration. We force RGBX here to fix it. */
70 surfaceformat = HAL_PIXEL_FORMAT_RGBX_8888;
71 }
72
73 err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
74 ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
75 if (!err) {
76 err = hwc_open_1(mModule, &mHwc);
77 ALOGE_IF(err, "%s device failed to initialize (%s)",
78 HWC_HARDWARE_COMPOSER, strerror(-err));
79 }
80
81 /* Fallback on the FB rendering path instead of trying to support HWC 1.0 */
82 if (!err && mHwc->common.version == HWC_DEVICE_API_VERSION_1_0) {
83 hwc_close_1(mHwc);
84 mHwc = nullptr;
85 }
86
87 if (!err && mHwc) {
88 if (mFBDevice) {
89 framebuffer_close(mFBDevice);
90 mFBDevice = nullptr;
91 }
92
93 int32_t values[3];
94 const uint32_t attrs[] = {
95 HWC_DISPLAY_WIDTH,
96 HWC_DISPLAY_HEIGHT,
97 HWC_DISPLAY_DPI_X,
98 HWC_DISPLAY_NO_ATTRIBUTE
99 };
100 mHwc->getDisplayAttributes(mHwc, 0, 0, attrs, values);
101
102 mWidth = values[0];
103 mHeight = values[1];
104 xdpi = values[2] / 1000.0f;
105 surfaceformat = HAL_PIXEL_FORMAT_RGBA_8888;
106 }
107
108 err = hw_get_module(POWER_HARDWARE_MODULE_ID,
109 (hw_module_t const**)&mPowerModule);
110 if (!err)
111 mPowerModule->init(mPowerModule);
112 ALOGW_IF(err, "Couldn't load %s module (%s)", POWER_HARDWARE_MODULE_ID, strerror(-err));
113
114 mAlloc = new GraphicBufferAlloc();
115
116 CreateFramebufferSurface(mSTClient, mDispSurface, mWidth, mHeight);
117
118 mList = (hwc_display_contents_1_t *)calloc(1, sizeof(*mList) + (sizeof(hwc_layer_1_t)*2));
119
120 uint32_t usage = GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
121 if (mFBDevice) {
122 // If device uses fb, they can not use single buffer for boot animation
123 mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_BUFFER_COUNT, 2);
124 mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_USAGE, usage);
125 } else if (mHwc) {
126 PowerOnDisplay(HWC_DISPLAY_PRIMARY);
127 // For devices w/ hwc v1.0 or no hwc, this buffer can not be created,
128 // only create this buffer for devices w/ hwc version > 1.0.
129 CreateFramebufferSurface(mBootAnimSTClient, mBootAnimDispSurface, mWidth, mHeight);
130 }
131 }
132
~GonkDisplayJB()133 GonkDisplayJB::~GonkDisplayJB()
134 {
135 if (mHwc)
136 hwc_close_1(mHwc);
137 if (mFBDevice)
138 framebuffer_close(mFBDevice);
139 free(mList);
140 }
141
142 void
CreateFramebufferSurface(android::sp<ANativeWindow> & aNativeWindow,android::sp<android::DisplaySurface> & aDisplaySurface,uint32_t aWidth,uint32_t aHeight)143 GonkDisplayJB::CreateFramebufferSurface(android::sp<ANativeWindow>& aNativeWindow,
144 android::sp<android::DisplaySurface>& aDisplaySurface,
145 uint32_t aWidth,
146 uint32_t aHeight)
147 {
148 #if ANDROID_VERSION >= 21
149 sp<IGraphicBufferProducer> producer;
150 sp<IGraphicBufferConsumer> consumer;
151 BufferQueue::createBufferQueue(&producer, &consumer, mAlloc);
152 #elif ANDROID_VERSION >= 19
153 sp<BufferQueue> consumer = new BufferQueue(mAlloc);
154 sp<IGraphicBufferProducer> producer = consumer;
155 #elif ANDROID_VERSION >= 18
156 sp<BufferQueue> consumer = new BufferQueue(true, mAlloc);
157 sp<IGraphicBufferProducer> producer = consumer;
158 #else
159 sp<BufferQueue> consumer = new BufferQueue(true, mAlloc);
160 #endif
161
162 aDisplaySurface = new FramebufferSurface(0, aWidth, aHeight, surfaceformat, consumer);
163
164 #if ANDROID_VERSION == 17
165 aNativeWindow = new SurfaceTextureClient(
166 static_cast<sp<ISurfaceTexture>>(aDisplaySurface->getBufferQueue()));
167 #else
168 aNativeWindow = new Surface(producer);
169 #endif
170 }
171
172 void
CreateVirtualDisplaySurface(android::IGraphicBufferProducer * aSink,android::sp<ANativeWindow> & aNativeWindow,android::sp<android::DisplaySurface> & aDisplaySurface)173 GonkDisplayJB::CreateVirtualDisplaySurface(android::IGraphicBufferProducer* aSink,
174 android::sp<ANativeWindow>& aNativeWindow,
175 android::sp<android::DisplaySurface>& aDisplaySurface)
176 {
177 #if ANDROID_VERSION >= 21
178 sp<IGraphicBufferProducer> producer;
179 sp<IGraphicBufferConsumer> consumer;
180 BufferQueue::createBufferQueue(&producer, &consumer, mAlloc);
181 #elif ANDROID_VERSION >= 19
182 sp<BufferQueue> consumer = new BufferQueue(mAlloc);
183 sp<IGraphicBufferProducer> producer = consumer;
184 #endif
185
186 #if ANDROID_VERSION >= 19
187 sp<VirtualDisplaySurface> virtualDisplay;
188 virtualDisplay = new VirtualDisplaySurface(-1, aSink, producer, consumer, String8("VirtualDisplaySurface"));
189 aDisplaySurface = virtualDisplay;
190 aNativeWindow = new Surface(virtualDisplay);
191 #endif
192 }
193
194 void
SetEnabled(bool enabled)195 GonkDisplayJB::SetEnabled(bool enabled)
196 {
197 if (enabled) {
198 autosuspend_disable();
199 mPowerModule->setInteractive(mPowerModule, true);
200 }
201
202 if (!enabled && mEnabledCallback) {
203 mEnabledCallback(enabled);
204 }
205
206 #if ANDROID_VERSION >= 21
207 if (mHwc) {
208 if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_4) {
209 mHwc->setPowerMode(mHwc, HWC_DISPLAY_PRIMARY,
210 (enabled ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF));
211 } else {
212 mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, !enabled);
213 }
214 } else if (mFBDevice && mFBDevice->enableScreen) {
215 mFBDevice->enableScreen(mFBDevice, enabled);
216 }
217 #else
218 if (mHwc && mHwc->blank) {
219 mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, !enabled);
220 } else if (mFBDevice && mFBDevice->enableScreen) {
221 mFBDevice->enableScreen(mFBDevice, enabled);
222 }
223 #endif
224
225 if (enabled && mEnabledCallback) {
226 mEnabledCallback(enabled);
227 }
228
229 if (!enabled) {
230 autosuspend_enable();
231 mPowerModule->setInteractive(mPowerModule, false);
232 }
233 }
234
235 void
OnEnabled(OnEnabledCallbackType callback)236 GonkDisplayJB::OnEnabled(OnEnabledCallbackType callback)
237 {
238 mEnabledCallback = callback;
239 }
240
241 void*
GetHWCDevice()242 GonkDisplayJB::GetHWCDevice()
243 {
244 return mHwc;
245 }
246
247 bool
SwapBuffers(EGLDisplay dpy,EGLSurface sur)248 GonkDisplayJB::SwapBuffers(EGLDisplay dpy, EGLSurface sur)
249 {
250 // Should be called when composition rendering is complete for a frame.
251 // Only HWC v1.0 needs this call.
252 // HWC > v1.0 case, do not call compositionComplete().
253 // mFBDevice is present only when HWC is v1.0.
254 if (mFBDevice && mFBDevice->compositionComplete) {
255 mFBDevice->compositionComplete(mFBDevice);
256 }
257 return Post(mDispSurface->lastHandle, mDispSurface->GetPrevDispAcquireFd());
258 }
259
260 bool
Post(buffer_handle_t buf,int fence)261 GonkDisplayJB::Post(buffer_handle_t buf, int fence)
262 {
263 if (!mHwc) {
264 if (fence >= 0)
265 close(fence);
266 return !mFBDevice->post(mFBDevice, buf);
267 }
268
269 hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = {NULL};
270 const hwc_rect_t r = { 0, 0, static_cast<int>(mWidth), static_cast<int>(mHeight) };
271 displays[HWC_DISPLAY_PRIMARY] = mList;
272 mList->retireFenceFd = -1;
273 mList->numHwLayers = 2;
274 mList->flags = HWC_GEOMETRY_CHANGED;
275 #if ANDROID_VERSION >= 18
276 mList->outbuf = nullptr;
277 mList->outbufAcquireFenceFd = -1;
278 #endif
279 mList->hwLayers[0].compositionType = HWC_FRAMEBUFFER;
280 mList->hwLayers[0].hints = 0;
281 /* Skip this layer so the hwc module doesn't complain about null handles */
282 mList->hwLayers[0].flags = HWC_SKIP_LAYER;
283 mList->hwLayers[0].backgroundColor = {0};
284 mList->hwLayers[0].acquireFenceFd = -1;
285 mList->hwLayers[0].releaseFenceFd = -1;
286 /* hwc module checks displayFrame even though it shouldn't */
287 mList->hwLayers[0].displayFrame = r;
288 mList->hwLayers[1].compositionType = HWC_FRAMEBUFFER_TARGET;
289 mList->hwLayers[1].hints = 0;
290 mList->hwLayers[1].flags = 0;
291 mList->hwLayers[1].handle = buf;
292 mList->hwLayers[1].transform = 0;
293 mList->hwLayers[1].blending = HWC_BLENDING_NONE;
294 #if ANDROID_VERSION >= 19
295 if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_3) {
296 mList->hwLayers[1].sourceCropf.left = 0;
297 mList->hwLayers[1].sourceCropf.top = 0;
298 mList->hwLayers[1].sourceCropf.right = mWidth;
299 mList->hwLayers[1].sourceCropf.bottom = mHeight;
300 } else {
301 mList->hwLayers[1].sourceCrop = r;
302 }
303 #else
304 mList->hwLayers[1].sourceCrop = r;
305 #endif
306 mList->hwLayers[1].displayFrame = r;
307 mList->hwLayers[1].visibleRegionScreen.numRects = 1;
308 mList->hwLayers[1].visibleRegionScreen.rects = &mList->hwLayers[1].displayFrame;
309 mList->hwLayers[1].acquireFenceFd = fence;
310 mList->hwLayers[1].releaseFenceFd = -1;
311 #if ANDROID_VERSION >= 18
312 mList->hwLayers[1].planeAlpha = 0xFF;
313 #endif
314 mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
315 int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
316
317 if (!mBootAnimDispSurface.get()) {
318 mDispSurface->setReleaseFenceFd(mList->hwLayers[1].releaseFenceFd);
319 } else {
320 mBootAnimDispSurface->setReleaseFenceFd(mList->hwLayers[1].releaseFenceFd);
321 }
322
323 if (mList->retireFenceFd >= 0)
324 close(mList->retireFenceFd);
325 return !err;
326 }
327
328 ANativeWindowBuffer*
DequeueBuffer()329 GonkDisplayJB::DequeueBuffer()
330 {
331 // Check for bootAnim or normal display flow.
332 sp<ANativeWindow> nativeWindow =
333 !mBootAnimSTClient.get() ? mSTClient : mBootAnimSTClient;
334
335 ANativeWindowBuffer *buf;
336 int fenceFd = -1;
337 nativeWindow->dequeueBuffer(nativeWindow.get(), &buf, &fenceFd);
338 sp<Fence> fence(new Fence(fenceFd));
339 #if ANDROID_VERSION == 17
340 fence->waitForever(1000, "GonkDisplayJB_DequeueBuffer");
341 // 1000 is what Android uses. It is a warning timeout in ms.
342 // This timeout was removed in ANDROID_VERSION 18.
343 #else
344 fence->waitForever("GonkDisplayJB_DequeueBuffer");
345 #endif
346 return buf;
347 }
348
349 bool
QueueBuffer(ANativeWindowBuffer * buf)350 GonkDisplayJB::QueueBuffer(ANativeWindowBuffer* buf)
351 {
352 bool success = false;
353 int error = DoQueueBuffer(buf);
354 // Check for bootAnim or normal display flow.
355 if (!mBootAnimSTClient.get()) {
356 success = Post(mDispSurface->lastHandle, mDispSurface->GetPrevDispAcquireFd());
357 } else {
358 success = Post(mBootAnimDispSurface->lastHandle, mBootAnimDispSurface->GetPrevDispAcquireFd());
359 }
360 return error == 0 && success;
361 }
362
363 int
DoQueueBuffer(ANativeWindowBuffer * buf)364 GonkDisplayJB::DoQueueBuffer(ANativeWindowBuffer* buf)
365 {
366 int error = 0;
367 // Check for bootAnim or normal display flow.
368 if (!mBootAnimSTClient.get()) {
369 error = mSTClient->queueBuffer(mSTClient.get(), buf, -1);
370 } else {
371 error = mBootAnimSTClient->queueBuffer(mBootAnimSTClient.get(), buf, -1);
372 }
373 return error;
374 }
375
376 void
UpdateDispSurface(EGLDisplay dpy,EGLSurface sur)377 GonkDisplayJB::UpdateDispSurface(EGLDisplay dpy, EGLSurface sur)
378 {
379 if (sur != EGL_NO_SURFACE) {
380 eglSwapBuffers(dpy, sur);
381 } else {
382 // When BasicCompositor is used as Compositor,
383 // EGLSurface does not exit.
384 ANativeWindowBuffer* buf = DequeueBuffer();
385 DoQueueBuffer(buf);
386 }
387 }
388
389 void
NotifyBootAnimationStopped()390 GonkDisplayJB::NotifyBootAnimationStopped()
391 {
392 if (mBootAnimSTClient.get()) {
393 mBootAnimSTClient = nullptr;
394 mBootAnimDispSurface = nullptr;
395 }
396 }
397
398 void
PowerOnDisplay(int aDpy)399 GonkDisplayJB::PowerOnDisplay(int aDpy)
400 {
401 MOZ_ASSERT(mHwc);
402 #if ANDROID_VERSION >= 21
403 if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_4) {
404 mHwc->setPowerMode(mHwc, aDpy, HWC_POWER_MODE_NORMAL);
405 } else {
406 mHwc->blank(mHwc, aDpy, 0);
407 }
408 #else
409 mHwc->blank(mHwc, aDpy, 0);
410 #endif
411 }
412
413 GonkDisplay::NativeData
GetNativeData(GonkDisplay::DisplayType aDisplayType,android::IGraphicBufferProducer * aSink)414 GonkDisplayJB::GetNativeData(GonkDisplay::DisplayType aDisplayType,
415 android::IGraphicBufferProducer* aSink)
416 {
417 NativeData data;
418
419 if (aDisplayType == DISPLAY_PRIMARY) {
420 data.mNativeWindow = mSTClient;
421 data.mDisplaySurface = mDispSurface;
422 data.mXdpi = xdpi;
423 } else if (aDisplayType == DISPLAY_EXTERNAL) {
424 int32_t values[3];
425 const uint32_t attrs[] = {
426 HWC_DISPLAY_WIDTH,
427 HWC_DISPLAY_HEIGHT,
428 HWC_DISPLAY_DPI_X,
429 HWC_DISPLAY_NO_ATTRIBUTE
430 };
431 mHwc->getDisplayAttributes(mHwc, aDisplayType, 0, attrs, values);
432 int width = values[0];
433 int height = values[1];
434 // FIXME!! values[2] returns 0 for external display, which doesn't
435 // sound right, Bug 1169176 is the follow-up bug for this issue.
436 data.mXdpi = values[2] ? values[2] / 1000.f : DEFAULT_XDPI;
437 PowerOnDisplay(HWC_DISPLAY_EXTERNAL);
438 CreateFramebufferSurface(data.mNativeWindow,
439 data.mDisplaySurface,
440 width,
441 height);
442 } else if (aDisplayType == DISPLAY_VIRTUAL) {
443 data.mXdpi = xdpi;
444 CreateVirtualDisplaySurface(aSink,
445 data.mNativeWindow,
446 data.mDisplaySurface);
447 }
448
449 return data;
450 }
451
452 __attribute__ ((visibility ("default")))
453 GonkDisplay*
GetGonkDisplay()454 GetGonkDisplay()
455 {
456 if (!sGonkDisplay)
457 sGonkDisplay = new GonkDisplayJB();
458 return sGonkDisplay;
459 }
460
461 } // namespace mozilla
462