michael@0: /* Copyright 2013 Mozilla Foundation and Mozilla contributors michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: #include "GonkDisplayICS.h" michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "mozilla/FileUtils.h" michael@0: #include "mozilla/NullPtr.h" michael@0: #include "mozilla/FileUtils.h" michael@0: michael@0: #include "BootAnimation.h" michael@0: michael@0: using namespace android; michael@0: michael@0: michael@0: namespace { michael@0: static const char* kSleepFile = "/sys/power/wait_for_fb_sleep"; michael@0: static const char* kWakeFile = "/sys/power/wait_for_fb_wake"; michael@0: static mozilla::GonkDisplay::OnEnabledCallbackType sEnabledCallback; michael@0: static pthread_t sFramebufferWatchThread; michael@0: michael@0: static void * michael@0: frameBufferWatcher(void *) michael@0: { michael@0: int len = 0; michael@0: char buf; michael@0: michael@0: while (true) { michael@0: // Cannot use epoll here because kSleepFile and kWakeFile are michael@0: // always ready to read and blocking. michael@0: { michael@0: mozilla::ScopedClose fd(open(kSleepFile, O_RDONLY, 0)); michael@0: do { michael@0: len = read(fd.get(), &buf, 1); michael@0: } while (len < 0 && errno == EINTR); michael@0: NS_WARN_IF_FALSE(len >= 0, "WAIT_FOR_FB_SLEEP failed"); michael@0: } michael@0: sEnabledCallback(false); michael@0: michael@0: { michael@0: mozilla::ScopedClose fd(open(kWakeFile, O_RDONLY, 0)); michael@0: do { michael@0: len = read(fd.get(), &buf, 1); michael@0: } while (len < 0 && errno == EINTR); michael@0: NS_WARN_IF_FALSE(len >= 0, "WAIT_FOR_FB_WAKE failed"); michael@0: } michael@0: sEnabledCallback(true); michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: } // anonymous namespace michael@0: michael@0: michael@0: namespace mozilla { michael@0: michael@0: static GonkDisplayICS* sGonkDisplay = nullptr; michael@0: michael@0: static int michael@0: FramebufferNativeWindowCancelBufferNoop(ANativeWindow* aWindow, michael@0: android_native_buffer_t* aBuffer) michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: GonkDisplayICS::GonkDisplayICS() michael@0: : mModule(nullptr) michael@0: , mHwc(nullptr) michael@0: { michael@0: // Some gralloc HALs need this in order to open the michael@0: // framebuffer device after we restart with the screen off. michael@0: // michael@0: // this *must* run BEFORE allocating the michael@0: // FramebufferNativeWindow. michael@0: set_screen_state(1); michael@0: michael@0: // For some devices, it takes a while for the framebuffer to become michael@0: // usable. So we wait until the framebuffer has woken up before we michael@0: // try to open it. michael@0: { michael@0: char buf; michael@0: int len = 0; michael@0: ScopedClose fd(open("/sys/power/wait_for_fb_wake", O_RDONLY, 0)); michael@0: do { michael@0: len = read(fd.get(), &buf, 1); michael@0: } while (len < 0 && errno == EINTR); michael@0: if (len < 0) { michael@0: LOGE("BootAnimation: wait_for_fb_sleep failed errno: %d", errno); michael@0: } michael@0: } michael@0: michael@0: mFBSurface = new FramebufferNativeWindow(); michael@0: michael@0: // ICS FramebufferNativeWindow doesn't set the |cancelBuffer| michael@0: // function pointer. michael@0: // It will crash when deleting the EGL window surface. michael@0: if (!mFBSurface->cancelBuffer) { michael@0: mFBSurface->cancelBuffer = FramebufferNativeWindowCancelBufferNoop; michael@0: } michael@0: michael@0: int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule); michael@0: LOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID); michael@0: if (!err) { michael@0: err = hwc_open(mModule, &mHwc); michael@0: LOGE_IF(err, "%s device failed to initialize (%s)", michael@0: HWC_HARDWARE_COMPOSER, strerror(-err)); michael@0: } michael@0: michael@0: xdpi = mFBSurface->xdpi; michael@0: michael@0: const framebuffer_device_t *fbdev = mFBSurface->getDevice(); michael@0: surfaceformat = fbdev->format; michael@0: michael@0: StartBootAnimation(); michael@0: } michael@0: michael@0: GonkDisplayICS::~GonkDisplayICS() michael@0: { michael@0: if (mHwc) michael@0: hwc_close(mHwc); michael@0: } michael@0: michael@0: ANativeWindow* michael@0: GonkDisplayICS::GetNativeWindow() michael@0: { michael@0: StopBootAnimation(); michael@0: return static_cast(mFBSurface.get()); michael@0: } michael@0: michael@0: void michael@0: GonkDisplayICS::SetEnabled(bool enabled) michael@0: { michael@0: set_screen_state(enabled); michael@0: } michael@0: michael@0: void michael@0: GonkDisplayICS::OnEnabled(OnEnabledCallbackType callback) michael@0: { michael@0: if (sEnabledCallback) michael@0: return; michael@0: sEnabledCallback = callback; michael@0: michael@0: // Watching screen on/off state by using a pthread michael@0: // which implicitly calls exit() when the main thread ends michael@0: if (pthread_create(&sFramebufferWatchThread, NULL, frameBufferWatcher, NULL)) { michael@0: NS_RUNTIMEABORT("Failed to create framebufferWatcherThread, aborting..."); michael@0: } michael@0: } michael@0: michael@0: michael@0: void* michael@0: GonkDisplayICS::GetHWCDevice() michael@0: { michael@0: return mHwc; michael@0: } michael@0: michael@0: void* michael@0: GonkDisplayICS::GetFBSurface() michael@0: { michael@0: return mFBSurface.get(); michael@0: } michael@0: michael@0: bool michael@0: GonkDisplayICS::SwapBuffers(EGLDisplay dpy, EGLSurface sur) michael@0: { michael@0: // Should be called when composition rendering is complete for a frame. michael@0: // Only HWC v1.0 needs this call. ICS gonk always needs the call. michael@0: mFBSurface->compositionComplete(); michael@0: michael@0: if (!mHwc) michael@0: return eglSwapBuffers(dpy, sur); michael@0: michael@0: mHwc->prepare(mHwc, nullptr); michael@0: return !mHwc->set(mHwc, dpy, sur, 0); michael@0: } michael@0: michael@0: ANativeWindowBuffer* michael@0: GonkDisplayICS::DequeueBuffer() michael@0: { michael@0: ANativeWindow *window = static_cast(mFBSurface.get()); michael@0: ANativeWindowBuffer *buf = nullptr; michael@0: window->dequeueBuffer(window, &buf); michael@0: return buf; michael@0: } michael@0: michael@0: bool michael@0: GonkDisplayICS::QueueBuffer(ANativeWindowBuffer *buf) michael@0: { michael@0: ANativeWindow *window = static_cast(mFBSurface.get()); michael@0: return !window->queueBuffer(window, buf); michael@0: } michael@0: michael@0: void michael@0: GonkDisplayICS::UpdateFBSurface(EGLDisplay dpy, EGLSurface sur) michael@0: { michael@0: eglSwapBuffers(dpy, sur); michael@0: } michael@0: michael@0: void michael@0: GonkDisplayICS::SetFBReleaseFd(int fd) michael@0: { michael@0: } michael@0: michael@0: __attribute__ ((visibility ("default"))) michael@0: GonkDisplay* michael@0: GetGonkDisplay() michael@0: { michael@0: if (!sGonkDisplay) michael@0: sGonkDisplay = new GonkDisplayICS(); michael@0: return sGonkDisplay; michael@0: } michael@0: michael@0: } // namespace mozilla