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 "GonkDisplayJB.h" michael@0: #if ANDROID_VERSION == 17 michael@0: #include michael@0: #else michael@0: #include michael@0: #include michael@0: #endif michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #if ANDROID_VERSION == 17 michael@0: #include "GraphicBufferAlloc.h" michael@0: #endif michael@0: #include "BootAnimation.h" michael@0: michael@0: using namespace android; michael@0: michael@0: namespace mozilla { michael@0: michael@0: static GonkDisplayJB* sGonkDisplay = nullptr; michael@0: michael@0: GonkDisplayJB::GonkDisplayJB() michael@0: : mList(nullptr) michael@0: , mModule(nullptr) michael@0: , mFBModule(nullptr) michael@0: , mHwc(nullptr) michael@0: , mFBDevice(nullptr) michael@0: , mEnabledCallback(nullptr) michael@0: , mPowerModule(nullptr) michael@0: { michael@0: int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mFBModule); michael@0: ALOGW_IF(err, "%s module not found", GRALLOC_HARDWARE_MODULE_ID); michael@0: if (!err) { michael@0: err = framebuffer_open(mFBModule, &mFBDevice); michael@0: ALOGW_IF(err, "could not open framebuffer"); michael@0: } michael@0: michael@0: if (!err && mFBDevice) { michael@0: mWidth = mFBDevice->width; michael@0: mHeight = mFBDevice->height; michael@0: xdpi = mFBDevice->xdpi; michael@0: /* The emulator actually reports RGBA_8888, but EGL doesn't return michael@0: * any matching configuration. We force RGBX here to fix it. */ michael@0: surfaceformat = HAL_PIXEL_FORMAT_RGBX_8888; michael@0: } michael@0: michael@0: err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule); michael@0: ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID); michael@0: if (!err) { michael@0: err = hwc_open_1(mModule, &mHwc); michael@0: ALOGE_IF(err, "%s device failed to initialize (%s)", michael@0: HWC_HARDWARE_COMPOSER, strerror(-err)); michael@0: } michael@0: michael@0: /* Fallback on the FB rendering path instead of trying to support HWC 1.0 */ michael@0: if (!err && mHwc->common.version == HWC_DEVICE_API_VERSION_1_0) { michael@0: hwc_close_1(mHwc); michael@0: mHwc = nullptr; michael@0: } michael@0: michael@0: if (!err && mHwc) { michael@0: if (mFBDevice) { michael@0: framebuffer_close(mFBDevice); michael@0: mFBDevice = nullptr; michael@0: } michael@0: michael@0: int32_t values[3]; michael@0: const uint32_t attrs[] = { michael@0: HWC_DISPLAY_WIDTH, michael@0: HWC_DISPLAY_HEIGHT, michael@0: HWC_DISPLAY_DPI_X, michael@0: HWC_DISPLAY_NO_ATTRIBUTE michael@0: }; michael@0: mHwc->getDisplayAttributes(mHwc, 0, 0, attrs, values); michael@0: michael@0: mWidth = values[0]; michael@0: mHeight = values[1]; michael@0: xdpi = values[2] / 1000.0f; michael@0: surfaceformat = HAL_PIXEL_FORMAT_RGBA_8888; michael@0: } michael@0: michael@0: err = hw_get_module(POWER_HARDWARE_MODULE_ID, michael@0: (hw_module_t const**)&mPowerModule); michael@0: if (!err) michael@0: mPowerModule->init(mPowerModule); michael@0: ALOGW_IF(err, "Couldn't load %s module (%s)", POWER_HARDWARE_MODULE_ID, strerror(-err)); michael@0: michael@0: mAlloc = new GraphicBufferAlloc(); michael@0: michael@0: status_t error; michael@0: uint32_t usage = GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER; michael@0: mBootAnimBuffer = mAlloc->createGraphicBuffer(mWidth, mHeight, surfaceformat, usage, &error); michael@0: if (error != NO_ERROR || !mBootAnimBuffer.get()) { michael@0: ALOGI("Trying to create BRGA format framebuffer"); michael@0: surfaceformat = HAL_PIXEL_FORMAT_BGRA_8888; michael@0: mBootAnimBuffer = mAlloc->createGraphicBuffer(mWidth, mHeight, surfaceformat, usage, &error); michael@0: } michael@0: michael@0: #if ANDROID_VERSION >= 19 michael@0: sp bq = new BufferQueue(mAlloc); michael@0: #else michael@0: sp bq = new BufferQueue(true, mAlloc); michael@0: #endif michael@0: mFBSurface = new FramebufferSurface(0, mWidth, mHeight, surfaceformat, bq); michael@0: michael@0: #if ANDROID_VERSION == 17 michael@0: sp stc = new SurfaceTextureClient(static_cast >(mFBSurface->getBufferQueue())); michael@0: #else michael@0: sp stc = new Surface(static_cast >(bq)); michael@0: #endif michael@0: mSTClient = stc; michael@0: michael@0: mList = (hwc_display_contents_1_t *)malloc(sizeof(*mList) + (sizeof(hwc_layer_1_t)*2)); michael@0: if (mHwc) michael@0: mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, 0); michael@0: michael@0: if (error == NO_ERROR && mBootAnimBuffer.get()) { michael@0: ALOGI("Starting bootanimation with (%d) format framebuffer", surfaceformat); michael@0: StartBootAnimation(); michael@0: } else michael@0: ALOGW("Couldn't show bootanimation (%s)", strerror(-error)); michael@0: } michael@0: michael@0: GonkDisplayJB::~GonkDisplayJB() michael@0: { michael@0: if (mHwc) michael@0: hwc_close_1(mHwc); michael@0: if (mFBDevice) michael@0: framebuffer_close(mFBDevice); michael@0: free(mList); michael@0: } michael@0: michael@0: ANativeWindow* michael@0: GonkDisplayJB::GetNativeWindow() michael@0: { michael@0: return mSTClient.get(); michael@0: } michael@0: michael@0: void michael@0: GonkDisplayJB::SetEnabled(bool enabled) michael@0: { michael@0: if (enabled) { michael@0: autosuspend_disable(); michael@0: mPowerModule->setInteractive(mPowerModule, true); michael@0: } michael@0: michael@0: if (mHwc) michael@0: mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, !enabled); michael@0: else if (mFBDevice->enableScreen) michael@0: mFBDevice->enableScreen(mFBDevice, enabled); michael@0: michael@0: if (mEnabledCallback) michael@0: mEnabledCallback(enabled); michael@0: michael@0: if (!enabled) { michael@0: autosuspend_enable(); michael@0: mPowerModule->setInteractive(mPowerModule, false); michael@0: } michael@0: } michael@0: michael@0: void michael@0: GonkDisplayJB::OnEnabled(OnEnabledCallbackType callback) michael@0: { michael@0: mEnabledCallback = callback; michael@0: } michael@0: michael@0: void* michael@0: GonkDisplayJB::GetHWCDevice() michael@0: { michael@0: return mHwc; michael@0: } michael@0: michael@0: void* michael@0: GonkDisplayJB::GetFBSurface() michael@0: { michael@0: return mFBSurface.get(); michael@0: } michael@0: michael@0: bool michael@0: GonkDisplayJB::SwapBuffers(EGLDisplay dpy, EGLSurface sur) michael@0: { michael@0: StopBootAnimation(); michael@0: mBootAnimBuffer = nullptr; michael@0: michael@0: // Should be called when composition rendering is complete for a frame. michael@0: // Only HWC v1.0 needs this call. michael@0: // HWC > v1.0 case, do not call compositionComplete(). michael@0: // mFBDevice is present only when HWC is v1.0. michael@0: if (mFBDevice && mFBDevice->compositionComplete) { michael@0: mFBDevice->compositionComplete(mFBDevice); michael@0: } michael@0: michael@0: #if ANDROID_VERSION == 17 michael@0: mList->dpy = dpy; michael@0: mList->sur = sur; michael@0: #else michael@0: mList->outbuf = nullptr; michael@0: mList->outbufAcquireFenceFd = -1; michael@0: #endif michael@0: eglSwapBuffers(dpy, sur); michael@0: return Post(mFBSurface->lastHandle, mFBSurface->GetPrevFBAcquireFd()); michael@0: } michael@0: michael@0: bool michael@0: GonkDisplayJB::Post(buffer_handle_t buf, int fence) michael@0: { michael@0: if (!mHwc) { michael@0: if (fence >= 0) michael@0: close(fence); michael@0: return !mFBDevice->post(mFBDevice, buf); michael@0: } michael@0: michael@0: hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = {NULL}; michael@0: const hwc_rect_t r = { 0, 0, mWidth, mHeight }; michael@0: displays[HWC_DISPLAY_PRIMARY] = mList; michael@0: mList->retireFenceFd = -1; michael@0: mList->numHwLayers = 2; michael@0: mList->flags = HWC_GEOMETRY_CHANGED; michael@0: mList->hwLayers[0].compositionType = HWC_FRAMEBUFFER; michael@0: mList->hwLayers[0].hints = 0; michael@0: /* Skip this layer so the hwc module doesn't complain about null handles */ michael@0: mList->hwLayers[0].flags = HWC_SKIP_LAYER; michael@0: mList->hwLayers[0].backgroundColor = {0}; michael@0: mList->hwLayers[0].acquireFenceFd = -1; michael@0: mList->hwLayers[0].releaseFenceFd = -1; michael@0: /* hwc module checks displayFrame even though it shouldn't */ michael@0: mList->hwLayers[0].displayFrame = r; michael@0: mList->hwLayers[1].compositionType = HWC_FRAMEBUFFER_TARGET; michael@0: mList->hwLayers[1].hints = 0; michael@0: mList->hwLayers[1].flags = 0; michael@0: mList->hwLayers[1].handle = buf; michael@0: mList->hwLayers[1].transform = 0; michael@0: mList->hwLayers[1].blending = HWC_BLENDING_PREMULT; michael@0: #if ANDROID_VERSION >= 19 michael@0: if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_3) { michael@0: mList->hwLayers[1].sourceCropf.left = 0; michael@0: mList->hwLayers[1].sourceCropf.top = 0; michael@0: mList->hwLayers[1].sourceCropf.right = mWidth; michael@0: mList->hwLayers[1].sourceCropf.bottom = mHeight; michael@0: } else { michael@0: mList->hwLayers[1].sourceCrop = r; michael@0: } michael@0: #else michael@0: mList->hwLayers[1].sourceCrop = r; michael@0: #endif michael@0: mList->hwLayers[1].displayFrame = r; michael@0: mList->hwLayers[1].visibleRegionScreen.numRects = 1; michael@0: mList->hwLayers[1].visibleRegionScreen.rects = &mList->hwLayers[1].displayFrame; michael@0: mList->hwLayers[1].acquireFenceFd = fence; michael@0: mList->hwLayers[1].releaseFenceFd = -1; michael@0: #if ANDROID_VERSION == 18 michael@0: mList->hwLayers[1].planeAlpha = 0xFF; michael@0: #endif michael@0: mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays); michael@0: int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays); michael@0: mFBSurface->setReleaseFenceFd(mList->hwLayers[1].releaseFenceFd); michael@0: if (mList->retireFenceFd >= 0) michael@0: close(mList->retireFenceFd); michael@0: return !err; michael@0: } michael@0: michael@0: ANativeWindowBuffer* michael@0: GonkDisplayJB::DequeueBuffer() michael@0: { michael@0: return static_cast(mBootAnimBuffer.get()); michael@0: } michael@0: michael@0: bool michael@0: GonkDisplayJB::QueueBuffer(ANativeWindowBuffer* buf) michael@0: { michael@0: bool success = Post(buf->handle, -1); michael@0: return success; michael@0: } michael@0: michael@0: void michael@0: GonkDisplayJB::UpdateFBSurface(EGLDisplay dpy, EGLSurface sur) michael@0: { michael@0: StopBootAnimation(); michael@0: mBootAnimBuffer = nullptr; michael@0: eglSwapBuffers(dpy, sur); michael@0: } michael@0: michael@0: void michael@0: GonkDisplayJB::SetFBReleaseFd(int fd) michael@0: { michael@0: mFBSurface->setReleaseFenceFd(fd); michael@0: } michael@0: michael@0: int michael@0: GonkDisplayJB::GetPrevFBAcquireFd() michael@0: { michael@0: return mFBSurface->GetPrevFBAcquireFd(); 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 GonkDisplayJB(); michael@0: return sGonkDisplay; michael@0: } michael@0: michael@0: } // namespace mozilla