michael@0: /* michael@0: * Copyright (c) 2012, 2013 The Linux Foundation. All rights reserved. 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 michael@0: #include michael@0: michael@0: #include "libdisplay/GonkDisplay.h" michael@0: #include "Framebuffer.h" michael@0: #include "GLContext.h" // for GLContext michael@0: #include "HwcUtils.h" michael@0: #include "HwcComposer2D.h" michael@0: #include "mozilla/layers/LayerManagerComposite.h" michael@0: #include "mozilla/layers/PLayerTransaction.h" michael@0: #include "mozilla/layers/ShadowLayerUtilsGralloc.h" michael@0: #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL michael@0: #include "mozilla/StaticPtr.h" michael@0: #include "cutils/properties.h" michael@0: #include "gfx2DGlue.h" michael@0: michael@0: #if ANDROID_VERSION >= 17 michael@0: #include "libdisplay/FramebufferSurface.h" michael@0: #ifndef HWC_BLIT michael@0: #define HWC_BLIT (HWC_FRAMEBUFFER_TARGET + 1) michael@0: #endif michael@0: #endif michael@0: michael@0: #ifdef LOG_TAG michael@0: #undef LOG_TAG michael@0: #endif michael@0: #define LOG_TAG "HWComposer" michael@0: michael@0: /* michael@0: * By default the debug message of hwcomposer (LOG_DEBUG level) are undefined, michael@0: * but can be enabled by uncommenting HWC_DEBUG below. michael@0: */ michael@0: //#define HWC_DEBUG michael@0: michael@0: #ifdef HWC_DEBUG michael@0: #define LOGD(args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, ## args) michael@0: #else michael@0: #define LOGD(args...) ((void)0) michael@0: #endif michael@0: michael@0: #define LOGI(args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, ## args) michael@0: #define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ## args) michael@0: michael@0: #define LAYER_COUNT_INCREMENTS 5 michael@0: michael@0: using namespace android; michael@0: using namespace mozilla::layers; michael@0: michael@0: namespace mozilla { michael@0: michael@0: static StaticRefPtr sInstance; michael@0: michael@0: HwcComposer2D::HwcComposer2D() michael@0: : mHwc(nullptr) michael@0: , mList(nullptr) michael@0: , mMaxLayerCount(0) michael@0: , mColorFill(false) michael@0: , mRBSwapSupport(false) michael@0: #if ANDROID_VERSION >= 17 michael@0: , mPrevRetireFence(Fence::NO_FENCE) michael@0: , mPrevDisplayFence(Fence::NO_FENCE) michael@0: #endif michael@0: , mPrepared(false) michael@0: { michael@0: } michael@0: michael@0: HwcComposer2D::~HwcComposer2D() { michael@0: free(mList); michael@0: } michael@0: michael@0: int michael@0: HwcComposer2D::Init(hwc_display_t dpy, hwc_surface_t sur) michael@0: { michael@0: MOZ_ASSERT(!Initialized()); michael@0: michael@0: mHwc = (HwcDevice*)GetGonkDisplay()->GetHWCDevice(); michael@0: if (!mHwc) { michael@0: LOGE("Failed to initialize hwc"); michael@0: return -1; michael@0: } michael@0: michael@0: nsIntSize screenSize; michael@0: michael@0: mozilla::Framebuffer::GetSize(&screenSize); michael@0: mScreenRect = nsIntRect(nsIntPoint(0, 0), screenSize); michael@0: michael@0: #if ANDROID_VERSION >= 17 michael@0: int supported = 0; michael@0: michael@0: if (mHwc->query) { michael@0: if (mHwc->query(mHwc, HwcUtils::HWC_COLOR_FILL, &supported) == NO_ERROR) { michael@0: mColorFill = !!supported; michael@0: } michael@0: if (mHwc->query(mHwc, HwcUtils::HWC_FORMAT_RB_SWAP, &supported) == NO_ERROR) { michael@0: mRBSwapSupport = !!supported; michael@0: } michael@0: } else { michael@0: mColorFill = false; michael@0: mRBSwapSupport = false; michael@0: } michael@0: #else michael@0: char propValue[PROPERTY_VALUE_MAX]; michael@0: property_get("ro.display.colorfill", propValue, "0"); michael@0: mColorFill = (atoi(propValue) == 1) ? true : false; michael@0: mRBSwapSupport = true; michael@0: #endif michael@0: michael@0: mDpy = dpy; michael@0: mSur = sur; michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: HwcComposer2D* michael@0: HwcComposer2D::GetInstance() michael@0: { michael@0: if (!sInstance) { michael@0: LOGI("Creating new instance"); michael@0: sInstance = new HwcComposer2D(); michael@0: } michael@0: return sInstance; michael@0: } michael@0: michael@0: bool michael@0: HwcComposer2D::ReallocLayerList() michael@0: { michael@0: int size = sizeof(HwcList) + michael@0: ((mMaxLayerCount + LAYER_COUNT_INCREMENTS) * sizeof(HwcLayer)); michael@0: michael@0: HwcList* listrealloc = (HwcList*)realloc(mList, size); michael@0: michael@0: if (!listrealloc) { michael@0: return false; michael@0: } michael@0: michael@0: if (!mList) { michael@0: //first alloc, initialize michael@0: listrealloc->numHwLayers = 0; michael@0: listrealloc->flags = 0; michael@0: } michael@0: michael@0: mList = listrealloc; michael@0: mMaxLayerCount += LAYER_COUNT_INCREMENTS; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: HwcComposer2D::setCrop(HwcLayer* layer, hwc_rect_t srcCrop) michael@0: { michael@0: #if ANDROID_VERSION >= 19 michael@0: if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_3) { michael@0: layer->sourceCropf.left = srcCrop.left; michael@0: layer->sourceCropf.top = srcCrop.top; michael@0: layer->sourceCropf.right = srcCrop.right; michael@0: layer->sourceCropf.bottom = srcCrop.bottom; michael@0: } else { michael@0: layer->sourceCrop = srcCrop; michael@0: } michael@0: #else michael@0: layer->sourceCrop = srcCrop; michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: HwcComposer2D::setHwcGeometry(bool aGeometryChanged) michael@0: { michael@0: #if ANDROID_VERSION >= 19 michael@0: mList->flags = aGeometryChanged ? HWC_GEOMETRY_CHANGED : 0; michael@0: #else michael@0: mList->flags = HWC_GEOMETRY_CHANGED; michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: HwcComposer2D::PrepareLayerList(Layer* aLayer, michael@0: const nsIntRect& aClip, michael@0: const gfxMatrix& aParentTransform, michael@0: const gfxMatrix& aGLWorldTransform) michael@0: { michael@0: // NB: we fall off this path whenever there are container layers michael@0: // that require intermediate surfaces. That means all the michael@0: // GetEffective*() coordinates are relative to the framebuffer. michael@0: michael@0: bool fillColor = false; michael@0: michael@0: const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion(); michael@0: if (visibleRegion.IsEmpty()) { michael@0: return true; michael@0: } michael@0: michael@0: uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0)); michael@0: #if ANDROID_VERSION < 18 michael@0: if (opacity < 0xFF) { michael@0: LOGD("%s Layer has planar semitransparency which is unsupported", aLayer->Name()); michael@0: return false; michael@0: } michael@0: #endif michael@0: michael@0: nsIntRect clip; michael@0: if (!HwcUtils::CalculateClipRect(aParentTransform * aGLWorldTransform, michael@0: aLayer->GetEffectiveClipRect(), michael@0: aClip, michael@0: &clip)) michael@0: { michael@0: LOGD("%s Clip rect is empty. Skip layer", aLayer->Name()); michael@0: return true; michael@0: } michael@0: michael@0: // HWC supports only the following 2D transformations: michael@0: // michael@0: // Scaling via the sourceCrop and displayFrame in HwcLayer michael@0: // Translation via the sourceCrop and displayFrame in HwcLayer michael@0: // Rotation (in square angles only) via the HWC_TRANSFORM_ROT_* flags michael@0: // Reflection (horizontal and vertical) via the HWC_TRANSFORM_FLIP_* flags michael@0: // michael@0: // A 2D transform with PreservesAxisAlignedRectangles() has all the attributes michael@0: // above michael@0: gfxMatrix transform; michael@0: gfx3DMatrix transform3D; michael@0: gfx::To3DMatrix(aLayer->GetEffectiveTransform(), transform3D); michael@0: michael@0: if (!transform3D.Is2D(&transform) || !transform.PreservesAxisAlignedRectangles()) { michael@0: LOGD("Layer has a 3D transform or a non-square angle rotation"); michael@0: return false; michael@0: } michael@0: michael@0: michael@0: if (ContainerLayer* container = aLayer->AsContainerLayer()) { michael@0: nsAutoTArray children; michael@0: container->SortChildrenBy3DZOrder(children); michael@0: michael@0: for (uint32_t i = 0; i < children.Length(); i++) { michael@0: if (!PrepareLayerList(children[i], clip, transform, aGLWorldTransform)) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: LayerRenderState state = aLayer->GetRenderState(); michael@0: nsIntSize surfaceSize; michael@0: michael@0: if (state.mSurface.get()) { michael@0: surfaceSize = state.mSize; michael@0: } else { michael@0: if (aLayer->AsColorLayer() && mColorFill) { michael@0: fillColor = true; michael@0: } else { michael@0: LOGD("%s Layer doesn't have a gralloc buffer", aLayer->Name()); michael@0: return false; michael@0: } michael@0: } michael@0: // Buffer rotation is not to be confused with the angled rotation done by a transform matrix michael@0: // It's a fancy ThebesLayer feature used for scrolling michael@0: if (state.BufferRotated()) { michael@0: LOGD("%s Layer has a rotated buffer", aLayer->Name()); michael@0: return false; michael@0: } michael@0: michael@0: nsIntRect visibleRect = visibleRegion.GetBounds(); michael@0: michael@0: nsIntRect bufferRect; michael@0: if (fillColor) { michael@0: bufferRect = nsIntRect(visibleRect); michael@0: } else { michael@0: if(state.mHasOwnOffset) { michael@0: bufferRect = nsIntRect(state.mOffset.x, state.mOffset.y, michael@0: state.mSize.width, state.mSize.height); michael@0: } else { michael@0: //Since the buffer doesn't have its own offset, assign the whole michael@0: //surface size as its buffer bounds michael@0: bufferRect = nsIntRect(0, 0, state.mSize.width, state.mSize.height); michael@0: } michael@0: } michael@0: michael@0: hwc_rect_t sourceCrop, displayFrame; michael@0: if(!HwcUtils::PrepareLayerRects(visibleRect, michael@0: transform * aGLWorldTransform, michael@0: clip, michael@0: bufferRect, michael@0: state.YFlipped(), michael@0: &(sourceCrop), michael@0: &(displayFrame))) michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: // OK! We can compose this layer with hwc. michael@0: int current = mList ? mList->numHwLayers : 0; michael@0: michael@0: // Do not compose any layer below full-screen Opaque layer michael@0: // Note: It can be generalized to non-fullscreen Opaque layers. michael@0: bool isOpaque = (opacity == 0xFF) && (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE); michael@0: if (current && isOpaque) { michael@0: nsIntRect displayRect = nsIntRect(displayFrame.left, displayFrame.top, michael@0: displayFrame.right - displayFrame.left, displayFrame.bottom - displayFrame.top); michael@0: if (displayRect.Contains(mScreenRect)) { michael@0: // In z-order, all previous layers are below michael@0: // the current layer. We can ignore them now. michael@0: mList->numHwLayers = current = 0; michael@0: mHwcLayerMap.Clear(); michael@0: } michael@0: } michael@0: michael@0: if (!mList || current >= mMaxLayerCount) { michael@0: if (!ReallocLayerList() || current >= mMaxLayerCount) { michael@0: LOGE("PrepareLayerList failed! Could not increase the maximum layer count"); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: HwcLayer& hwcLayer = mList->hwLayers[current]; michael@0: hwcLayer.flags = 0; michael@0: michael@0: if (ContainerLayer* parent = aLayer->GetParent()) { michael@0: if (parent->UseIntermediateSurface()) { michael@0: LOGD("Parent container needs intermediate surface"); michael@0: hwcLayer.flags = HWC_SKIP_LAYER; michael@0: #if ANDROID_VERSION < 18 michael@0: // No partial HWC Composition on older versions michael@0: return false; michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: hwcLayer.displayFrame = displayFrame; michael@0: setCrop(&hwcLayer, sourceCrop); michael@0: buffer_handle_t handle = fillColor ? nullptr : state.mSurface->getNativeBuffer()->handle; michael@0: hwcLayer.handle = handle; michael@0: michael@0: hwcLayer.hints = 0; michael@0: hwcLayer.blending = isOpaque ? HWC_BLENDING_NONE : HWC_BLENDING_PREMULT; michael@0: #if ANDROID_VERSION >= 17 michael@0: hwcLayer.compositionType = HWC_FRAMEBUFFER; michael@0: michael@0: hwcLayer.acquireFenceFd = -1; michael@0: hwcLayer.releaseFenceFd = -1; michael@0: #if ANDROID_VERSION >= 18 michael@0: hwcLayer.planeAlpha = opacity; michael@0: #endif michael@0: #else michael@0: hwcLayer.compositionType = HwcUtils::HWC_USE_COPYBIT; michael@0: #endif michael@0: michael@0: if (!fillColor) { michael@0: if (state.FormatRBSwapped()) { michael@0: if (!mRBSwapSupport) { michael@0: LOGD("No R/B swap support in H/W Composer"); michael@0: return false; michael@0: } michael@0: hwcLayer.flags |= HwcUtils::HWC_FORMAT_RB_SWAP; michael@0: } michael@0: michael@0: // Translation and scaling have been addressed in PrepareLayerRects(). michael@0: // Given the above and that we checked for PreservesAxisAlignedRectangles() michael@0: // the only possible transformations left to address are michael@0: // square angle rotation and horizontal/vertical reflection. michael@0: // michael@0: // The rotation and reflection permutations total 16 but can be michael@0: // reduced to 8 transformations after eliminating redundancies. michael@0: // michael@0: // All matrices represented here are in the form michael@0: // michael@0: // | xx xy | michael@0: // | yx yy | michael@0: // michael@0: // And ignore scaling. michael@0: // michael@0: // Reflection is applied before rotation michael@0: gfxMatrix rotation = transform * aGLWorldTransform; michael@0: // Compute fuzzy zero like PreservesAxisAlignedRectangles() michael@0: if (fabs(rotation.xx) < 1e-6) { michael@0: if (rotation.xy < 0) { michael@0: if (rotation.yx > 0) { michael@0: // 90 degree rotation michael@0: // michael@0: // | 0 -1 | michael@0: // | 1 0 | michael@0: // michael@0: hwcLayer.transform = HWC_TRANSFORM_ROT_90; michael@0: LOGD("Layer rotated 90 degrees"); michael@0: } michael@0: else { michael@0: // Horizontal reflection then 90 degree rotation michael@0: // michael@0: // | 0 -1 | | -1 0 | = | 0 -1 | michael@0: // | 1 0 | | 0 1 | | -1 0 | michael@0: // michael@0: // same as vertical reflection then 270 degree rotation michael@0: // michael@0: // | 0 1 | | 1 0 | = | 0 -1 | michael@0: // | -1 0 | | 0 -1 | | -1 0 | michael@0: // michael@0: hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_H; michael@0: LOGD("Layer vertically reflected then rotated 270 degrees"); michael@0: } michael@0: } else { michael@0: if (rotation.yx < 0) { michael@0: // 270 degree rotation michael@0: // michael@0: // | 0 1 | michael@0: // | -1 0 | michael@0: // michael@0: hwcLayer.transform = HWC_TRANSFORM_ROT_270; michael@0: LOGD("Layer rotated 270 degrees"); michael@0: } michael@0: else { michael@0: // Vertical reflection then 90 degree rotation michael@0: // michael@0: // | 0 1 | | -1 0 | = | 0 1 | michael@0: // | -1 0 | | 0 1 | | 1 0 | michael@0: // michael@0: // Same as horizontal reflection then 270 degree rotation michael@0: // michael@0: // | 0 -1 | | 1 0 | = | 0 1 | michael@0: // | 1 0 | | 0 -1 | | 1 0 | michael@0: // michael@0: hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_V; michael@0: LOGD("Layer horizontally reflected then rotated 270 degrees"); michael@0: } michael@0: } michael@0: } else if (rotation.xx < 0) { michael@0: if (rotation.yy > 0) { michael@0: // Horizontal reflection michael@0: // michael@0: // | -1 0 | michael@0: // | 0 1 | michael@0: // michael@0: hwcLayer.transform = HWC_TRANSFORM_FLIP_H; michael@0: LOGD("Layer rotated 180 degrees"); michael@0: } michael@0: else { michael@0: // 180 degree rotation michael@0: // michael@0: // | -1 0 | michael@0: // | 0 -1 | michael@0: // michael@0: // Same as horizontal and vertical reflection michael@0: // michael@0: // | -1 0 | | 1 0 | = | -1 0 | michael@0: // | 0 1 | | 0 -1 | | 0 -1 | michael@0: // michael@0: hwcLayer.transform = HWC_TRANSFORM_ROT_180; michael@0: LOGD("Layer rotated 180 degrees"); michael@0: } michael@0: } else { michael@0: if (rotation.yy < 0) { michael@0: // Vertical reflection michael@0: // michael@0: // | 1 0 | michael@0: // | 0 -1 | michael@0: // michael@0: hwcLayer.transform = HWC_TRANSFORM_FLIP_V; michael@0: LOGD("Layer rotated 180 degrees"); michael@0: } michael@0: else { michael@0: // No rotation or reflection michael@0: // michael@0: // | 1 0 | michael@0: // | 0 1 | michael@0: // michael@0: hwcLayer.transform = 0; michael@0: } michael@0: } michael@0: michael@0: if (state.YFlipped()) { michael@0: // Invert vertical reflection flag if it was already set michael@0: hwcLayer.transform ^= HWC_TRANSFORM_FLIP_V; michael@0: } michael@0: hwc_region_t region; michael@0: if (visibleRegion.GetNumRects() > 1) { michael@0: mVisibleRegions.push_back(HwcUtils::RectVector()); michael@0: HwcUtils::RectVector* visibleRects = &(mVisibleRegions.back()); michael@0: if(!HwcUtils::PrepareVisibleRegion(visibleRegion, michael@0: transform * aGLWorldTransform, michael@0: clip, michael@0: bufferRect, michael@0: visibleRects)) { michael@0: return true; michael@0: } michael@0: region.numRects = visibleRects->size(); michael@0: region.rects = &((*visibleRects)[0]); michael@0: } else { michael@0: region.numRects = 1; michael@0: region.rects = &(hwcLayer.displayFrame); michael@0: } michael@0: hwcLayer.visibleRegionScreen = region; michael@0: } else { michael@0: hwcLayer.flags |= HwcUtils::HWC_COLOR_FILL; michael@0: ColorLayer* colorLayer = aLayer->AsColorLayer(); michael@0: if (colorLayer->GetColor().a < 1.0) { michael@0: LOGD("Color layer has semitransparency which is unsupported"); michael@0: return false; michael@0: } michael@0: hwcLayer.transform = colorLayer->GetColor().Packed(); michael@0: } michael@0: michael@0: mHwcLayerMap.AppendElement(static_cast(aLayer->ImplData())); michael@0: mList->numHwLayers++; michael@0: return true; michael@0: } michael@0: michael@0: michael@0: #if ANDROID_VERSION >= 17 michael@0: bool michael@0: HwcComposer2D::TryHwComposition() michael@0: { michael@0: FramebufferSurface* fbsurface = (FramebufferSurface*)(GetGonkDisplay()->GetFBSurface()); michael@0: michael@0: if (!(fbsurface && fbsurface->lastHandle)) { michael@0: LOGD("H/W Composition failed. FBSurface not initialized."); michael@0: return false; michael@0: } michael@0: michael@0: // Add FB layer michael@0: int idx = mList->numHwLayers++; michael@0: if (idx >= mMaxLayerCount) { michael@0: if (!ReallocLayerList() || idx >= mMaxLayerCount) { michael@0: LOGE("TryHwComposition failed! Could not add FB layer"); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: Prepare(fbsurface->lastHandle, -1); michael@0: michael@0: /* Possible composition paths, after hwc prepare: michael@0: 1. GPU Composition michael@0: 2. BLIT Composition michael@0: 3. Full OVERLAY Composition michael@0: 4. Partial OVERLAY Composition (GPU + OVERLAY) */ michael@0: michael@0: bool gpuComposite = false; michael@0: bool blitComposite = false; michael@0: bool overlayComposite = true; michael@0: michael@0: for (int j=0; j < idx; j++) { michael@0: if (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER || michael@0: mList->hwLayers[j].compositionType == HWC_BLIT) { michael@0: // Full OVERLAY composition is not possible on this frame michael@0: // It is either GPU / BLIT / partial OVERLAY composition. michael@0: overlayComposite = false; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (!overlayComposite) { michael@0: for (int k=0; k < idx; k++) { michael@0: switch (mList->hwLayers[k].compositionType) { michael@0: case HWC_FRAMEBUFFER: michael@0: gpuComposite = true; michael@0: break; michael@0: case HWC_BLIT: michael@0: blitComposite = true; michael@0: break; michael@0: case HWC_OVERLAY: michael@0: // HWC will compose HWC_OVERLAY layers in partial michael@0: // Overlay Composition, set layer composition flag michael@0: // on mapped LayerComposite to skip GPU composition michael@0: mHwcLayerMap[k]->SetLayerComposited(true); michael@0: if ((mList->hwLayers[k].hints & HWC_HINT_CLEAR_FB) && michael@0: (mList->hwLayers[k].blending == HWC_BLENDING_NONE)) { michael@0: // Clear visible rect on FB with transparent pixels. michael@0: hwc_rect_t r = mList->hwLayers[k].displayFrame; michael@0: mHwcLayerMap[k]->SetClearRect(nsIntRect(r.left, r.top, michael@0: r.right - r.left, michael@0: r.bottom - r.top)); michael@0: } michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (gpuComposite) { michael@0: // GPU or partial OVERLAY Composition michael@0: return false; michael@0: } else if (blitComposite) { michael@0: // BLIT Composition, flip FB target michael@0: GetGonkDisplay()->UpdateFBSurface(mDpy, mSur); michael@0: FramebufferSurface* fbsurface = (FramebufferSurface*)(GetGonkDisplay()->GetFBSurface()); michael@0: if (!fbsurface) { michael@0: LOGE("H/W Composition failed. NULL FBSurface."); michael@0: return false; michael@0: } michael@0: mList->hwLayers[idx].handle = fbsurface->lastHandle; michael@0: mList->hwLayers[idx].acquireFenceFd = fbsurface->GetPrevFBAcquireFd(); michael@0: } michael@0: } michael@0: michael@0: // BLIT or full OVERLAY Composition michael@0: Commit(); michael@0: michael@0: GetGonkDisplay()->SetFBReleaseFd(mList->hwLayers[idx].releaseFenceFd); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: HwcComposer2D::Render(EGLDisplay dpy, EGLSurface sur) michael@0: { michael@0: if (!mList) { michael@0: // After boot, HWC list hasn't been created yet michael@0: return GetGonkDisplay()->SwapBuffers(dpy, sur); michael@0: } michael@0: michael@0: GetGonkDisplay()->UpdateFBSurface(dpy, sur); michael@0: michael@0: FramebufferSurface* fbsurface = (FramebufferSurface*)(GetGonkDisplay()->GetFBSurface()); michael@0: if (!fbsurface) { michael@0: LOGE("H/W Composition failed. FBSurface not initialized."); michael@0: return false; michael@0: } michael@0: michael@0: if (mPrepared) { michael@0: // No mHwc prepare, if already prepared in current draw cycle michael@0: mList->hwLayers[mList->numHwLayers - 1].handle = fbsurface->lastHandle; michael@0: mList->hwLayers[mList->numHwLayers - 1].acquireFenceFd = fbsurface->GetPrevFBAcquireFd(); michael@0: } else { michael@0: mList->flags = HWC_GEOMETRY_CHANGED; michael@0: mList->numHwLayers = 2; michael@0: mList->hwLayers[0].hints = 0; michael@0: mList->hwLayers[0].compositionType = HWC_FRAMEBUFFER; 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: mList->hwLayers[0].displayFrame = {0, 0, mScreenRect.width, mScreenRect.height}; michael@0: Prepare(fbsurface->lastHandle, fbsurface->GetPrevFBAcquireFd()); michael@0: } michael@0: michael@0: // GPU or partial HWC Composition michael@0: Commit(); michael@0: michael@0: GetGonkDisplay()->SetFBReleaseFd(mList->hwLayers[mList->numHwLayers - 1].releaseFenceFd); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: HwcComposer2D::Prepare(buffer_handle_t fbHandle, int fence) michael@0: { michael@0: int idx = mList->numHwLayers - 1; michael@0: const hwc_rect_t r = {0, 0, mScreenRect.width, mScreenRect.height}; michael@0: hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr }; michael@0: michael@0: displays[HWC_DISPLAY_PRIMARY] = mList; michael@0: mList->outbufAcquireFenceFd = -1; michael@0: mList->outbuf = nullptr; michael@0: mList->retireFenceFd = -1; michael@0: michael@0: mList->hwLayers[idx].hints = 0; michael@0: mList->hwLayers[idx].flags = 0; michael@0: mList->hwLayers[idx].transform = 0; michael@0: mList->hwLayers[idx].handle = fbHandle; michael@0: mList->hwLayers[idx].blending = HWC_BLENDING_PREMULT; michael@0: mList->hwLayers[idx].compositionType = HWC_FRAMEBUFFER_TARGET; michael@0: setCrop(&mList->hwLayers[idx], r); michael@0: mList->hwLayers[idx].displayFrame = r; michael@0: mList->hwLayers[idx].visibleRegionScreen.numRects = 1; michael@0: mList->hwLayers[idx].visibleRegionScreen.rects = &mList->hwLayers[idx].displayFrame; michael@0: mList->hwLayers[idx].acquireFenceFd = fence; michael@0: mList->hwLayers[idx].releaseFenceFd = -1; michael@0: #if ANDROID_VERSION >= 18 michael@0: mList->hwLayers[idx].planeAlpha = 0xFF; michael@0: #endif michael@0: if (mPrepared) { michael@0: LOGE("Multiple hwc prepare calls!"); michael@0: } michael@0: mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays); michael@0: mPrepared = true; michael@0: } michael@0: michael@0: bool michael@0: HwcComposer2D::Commit() michael@0: { michael@0: hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr }; michael@0: displays[HWC_DISPLAY_PRIMARY] = mList; michael@0: michael@0: int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays); michael@0: michael@0: mPrevDisplayFence = mPrevRetireFence; michael@0: mPrevRetireFence = Fence::NO_FENCE; michael@0: michael@0: for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) { michael@0: if (mList->hwLayers[j].releaseFenceFd >= 0) { michael@0: int fd = mList->hwLayers[j].releaseFenceFd; michael@0: mList->hwLayers[j].releaseFenceFd = -1; michael@0: sp fence = new Fence(fd); michael@0: michael@0: LayerRenderState state = mHwcLayerMap[j]->GetLayer()->GetRenderState(); michael@0: if (!state.mTexture) { michael@0: continue; michael@0: } michael@0: TextureHostOGL* texture = state.mTexture->AsHostOGL(); michael@0: if (!texture) { michael@0: continue; michael@0: } michael@0: texture->SetReleaseFence(fence); michael@0: } michael@0: } michael@0: michael@0: if (mList->retireFenceFd >= 0) { michael@0: mPrevRetireFence = new Fence(mList->retireFenceFd); michael@0: } michael@0: michael@0: mPrepared = false; michael@0: return !err; michael@0: } michael@0: michael@0: void michael@0: HwcComposer2D::Reset() michael@0: { michael@0: LOGD("hwcomposer is already prepared, reset with null set"); michael@0: hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr }; michael@0: displays[HWC_DISPLAY_PRIMARY] = nullptr; michael@0: mHwc->set(mHwc, HWC_DISPLAY_PRIMARY, displays); michael@0: mPrepared = false; michael@0: } michael@0: #else michael@0: bool michael@0: HwcComposer2D::TryHwComposition() michael@0: { michael@0: return !mHwc->set(mHwc, mDpy, mSur, mList); michael@0: } michael@0: michael@0: bool michael@0: HwcComposer2D::Render(EGLDisplay dpy, EGLSurface sur) michael@0: { michael@0: return GetGonkDisplay()->SwapBuffers(dpy, sur); michael@0: } michael@0: michael@0: void michael@0: HwcComposer2D::Reset() michael@0: { michael@0: mPrepared = false; michael@0: } michael@0: #endif michael@0: michael@0: bool michael@0: HwcComposer2D::TryRender(Layer* aRoot, michael@0: const gfx::Matrix& GLWorldTransform, michael@0: bool aGeometryChanged) michael@0: { michael@0: gfxMatrix aGLWorldTransform = ThebesMatrix(GLWorldTransform); michael@0: if (!aGLWorldTransform.PreservesAxisAlignedRectangles()) { michael@0: LOGD("Render aborted. World transform has non-square angle rotation"); michael@0: return false; michael@0: } michael@0: michael@0: MOZ_ASSERT(Initialized()); michael@0: if (mList) { michael@0: setHwcGeometry(aGeometryChanged); michael@0: mList->numHwLayers = 0; michael@0: mHwcLayerMap.Clear(); michael@0: } michael@0: michael@0: if (mPrepared) { michael@0: Reset(); michael@0: } michael@0: michael@0: // XXX: The clear() below means all rect vectors will be have to be michael@0: // reallocated. We may want to avoid this if possible michael@0: mVisibleRegions.clear(); michael@0: michael@0: MOZ_ASSERT(mHwcLayerMap.IsEmpty()); michael@0: if (!PrepareLayerList(aRoot, michael@0: mScreenRect, michael@0: gfxMatrix(), michael@0: aGLWorldTransform)) michael@0: { michael@0: LOGD("Render aborted. Nothing was drawn to the screen"); michael@0: return false; michael@0: } michael@0: michael@0: if (!TryHwComposition()) { michael@0: LOGD("H/W Composition failed"); michael@0: return false; michael@0: } michael@0: michael@0: LOGD("Frame rendered"); michael@0: return true; michael@0: } michael@0: michael@0: } // namespace mozilla