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