bool HwcComposer2D::TryRender(Layer* aRoot, const gfxMatrix& aGLWorldTransform) { if (!aGLWorldTransform.PreservesAxisAlignedRectangles()) { LOGD("Render aborted. World transform has non-square angle rotation"); return false; } MOZ_ASSERT(Initialized()); if (mList) { mList->numHwLayers = 0; } if (!PrepareLayerList(aRoot, mScreenRect, gfxMatrix(), aGLWorldTransform)) { LOGD("Render aborted. Nothing was drawn to the screen"); return false; } if (mHwc->set(mHwc, mDpy, mSur, mList)) { LOGE("Hardware device failed to render"); return false; } LOGD("Frame rendered"); return true; }
bool HwcComposer2D::TryRender(Layer* aRoot, const gfxMatrix& aGLWorldTransform) { MOZ_ASSERT(Initialized()); if (mList) { mList->numHwLayers = 0; } // XXX use GL world transform instead of GetRotation() int rotation = GetRotation(); int fbHeight, fbWidth; if (rotation == 0 || rotation == HWC_TRANSFORM_ROT_180) { fbWidth = mScreenWidth; fbHeight = mScreenHeight; } else { fbWidth = mScreenHeight; fbHeight = mScreenWidth; } if (!PrepareLayerList(aRoot, nsIntRect(0, 0, fbWidth, fbHeight))) { LOGD("Render aborted. Nothing was drawn to the screen"); return false; } if (mHwc->set(mHwc, mDpy, mSur, mList)) { LOGE("Hardware device failed to render"); return false; } LOGD("Frame rendered"); return true; }
bool HwcComposer2D::TryRenderWithHwc(Layer* aRoot, nsIWidget* aWidget, bool aGeometryChanged) { if (!mHal->HasHwc()) { return false; } nsScreenGonk* screen = static_cast<nsWindow*>(aWidget)->GetScreen(); if (mList) { mList->flags = mHal->GetGeometryChangedFlag(aGeometryChanged); mList->numHwLayers = 0; mHwcLayerMap.Clear(); } if (mPrepared) { mHal->ResetHwc(); mPrepared = false; } // XXX: The clear() below means all rect vectors will be have to be // reallocated. We may want to avoid this if possible mVisibleRegions.clear(); mScreenRect = screen->GetNaturalBounds(); MOZ_ASSERT(mHwcLayerMap.IsEmpty()); if (!PrepareLayerList(aRoot, mScreenRect, gfx::Matrix())) { mHwcLayerMap.Clear(); LOGD("Render aborted. Nothing was drawn to the screen"); return false; } // Send data to LayerScope for debugging SendtoLayerScope(); if (!TryHwComposition(screen)) { LOGD("Full HWC Composition failed. Fallback to GPU Composition or partial OVERLAY Composition"); LayerScope::CleanLayer(); return false; } LOGD("Frame rendered"); return true; }
bool HwcComposer2D::TryRender(Layer* aRoot, const gfxMatrix& aGLWorldTransform) { if (!aGLWorldTransform.PreservesAxisAlignedRectangles()) { LOGD("Render aborted. World transform has non-square angle rotation"); return false; } MOZ_ASSERT(Initialized()); if (mList) { mList->numHwLayers = 0; mHwcLayerMap.Clear(); } if (mPrepared) { Reset(); } // XXX: The clear() below means all rect vectors will be have to be // reallocated. We may want to avoid this if possible mVisibleRegions.clear(); MOZ_ASSERT(mHwcLayerMap.IsEmpty()); if (!PrepareLayerList(aRoot, mScreenRect, gfxMatrix(), aGLWorldTransform)) { LOGD("Render aborted. Nothing was drawn to the screen"); return false; } if (!TryHwComposition()) { LOGD("H/W Composition failed"); return false; } LOGD("Frame rendered"); return true; }
bool HwcComposer2D::TryRender(Layer* aRoot, bool aGeometryChanged) { MOZ_ASSERT(Initialized()); if (mList) { setHwcGeometry(aGeometryChanged); mList->numHwLayers = 0; mHwcLayerMap.Clear(); } if (mPrepared) { Reset(); } // XXX: The clear() below means all rect vectors will be have to be // reallocated. We may want to avoid this if possible mVisibleRegions.clear(); MOZ_ASSERT(mHwcLayerMap.IsEmpty()); if (!PrepareLayerList(aRoot, mScreenRect, gfx::Matrix())) { mHwcLayerMap.Clear(); LOGD("Render aborted. Nothing was drawn to the screen"); return false; } // Send data to LayerScope for debugging SendtoLayerScope(); if (!TryHwComposition()) { LOGD("H/W Composition failed"); LayerScope::CleanLayer(); return false; } LOGD("Frame rendered"); return true; }
bool HwcComposer2D::PrepareLayerList(Layer* aLayer, const nsIntRect& aClip, const gfxMatrix& aParentTransform, const gfxMatrix& aGLWorldTransform) { // NB: we fall off this path whenever there are container layers // that require intermediate surfaces. That means all the // GetEffective*() coordinates are relative to the framebuffer. bool fillColor = false; const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion(); if (visibleRegion.IsEmpty()) { return true; } uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0)); #if ANDROID_VERSION < 18 if (opacity < 0xFF) { LOGD("%s Layer has planar semitransparency which is unsupported", aLayer->Name()); return false; } #endif nsIntRect clip; if (!HwcUtils::CalculateClipRect(aParentTransform * aGLWorldTransform, aLayer->GetEffectiveClipRect(), aClip, &clip)) { LOGD("%s Clip rect is empty. Skip layer", aLayer->Name()); return true; } // HWC supports only the following 2D transformations: // // Scaling via the sourceCrop and displayFrame in HwcLayer // Translation via the sourceCrop and displayFrame in HwcLayer // Rotation (in square angles only) via the HWC_TRANSFORM_ROT_* flags // Reflection (horizontal and vertical) via the HWC_TRANSFORM_FLIP_* flags // // A 2D transform with PreservesAxisAlignedRectangles() has all the attributes // above gfxMatrix transform; const gfx3DMatrix& transform3D = aLayer->GetEffectiveTransform(); if (!transform3D.Is2D(&transform) || !transform.PreservesAxisAlignedRectangles()) { LOGD("Layer has a 3D transform or a non-square angle rotation"); return false; } if (ContainerLayer* container = aLayer->AsContainerLayer()) { if (container->UseIntermediateSurface()) { LOGD("Container layer needs intermediate surface"); return false; } nsAutoTArray<Layer*, 12> children; container->SortChildrenBy3DZOrder(children); for (uint32_t i = 0; i < children.Length(); i++) { if (!PrepareLayerList(children[i], clip, transform, aGLWorldTransform)) { return false; } } return true; } LayerRenderState state = aLayer->GetRenderState(); nsIntSize surfaceSize; if (state.mSurface.get()) { surfaceSize = state.mSize; } else { if (aLayer->AsColorLayer() && mColorFill) { fillColor = true; } else { LOGD("%s Layer doesn't have a gralloc buffer", aLayer->Name()); return false; } } // Buffer rotation is not to be confused with the angled rotation done by a transform matrix // It's a fancy ThebesLayer feature used for scrolling if (state.BufferRotated()) { LOGD("%s Layer has a rotated buffer", aLayer->Name()); return false; } // OK! We can compose this layer with hwc. int current = mList ? mList->numHwLayers : 0; if (!mList || current >= mMaxLayerCount) { if (!ReallocLayerList() || current >= mMaxLayerCount) { LOGE("PrepareLayerList failed! Could not increase the maximum layer count"); return false; } } nsIntRect visibleRect = visibleRegion.GetBounds(); nsIntRect bufferRect; if (fillColor) { bufferRect = nsIntRect(visibleRect); } else { if(state.mHasOwnOffset) { bufferRect = nsIntRect(state.mOffset.x, state.mOffset.y, state.mSize.width, state.mSize.height); } else { //Since the buffer doesn't have its own offset, assign the whole //surface size as its buffer bounds bufferRect = nsIntRect(0, 0, state.mSize.width, state.mSize.height); } } HwcLayer& hwcLayer = mList->hwLayers[current]; if(!HwcUtils::PrepareLayerRects(visibleRect, transform * aGLWorldTransform, clip, bufferRect, &(hwcLayer.sourceCrop), &(hwcLayer.displayFrame))) { return true; } buffer_handle_t handle = fillColor ? nullptr : state.mSurface->getNativeBuffer()->handle; hwcLayer.handle = handle; hwcLayer.flags = 0; hwcLayer.hints = 0; hwcLayer.blending = HWC_BLENDING_PREMULT; #if ANDROID_VERSION >= 18 hwcLayer.compositionType = HWC_FRAMEBUFFER; hwcLayer.acquireFenceFd = -1; hwcLayer.releaseFenceFd = -1; hwcLayer.planeAlpha = opacity; #else hwcLayer.compositionType = HwcUtils::HWC_USE_COPYBIT; #endif if (!fillColor) { if (state.FormatRBSwapped()) { if (!mRBSwapSupport) { LOGD("No R/B swap support in H/W Composer"); return false; } hwcLayer.flags |= HwcUtils::HWC_FORMAT_RB_SWAP; } // Translation and scaling have been addressed in PrepareLayerRects(). // Given the above and that we checked for PreservesAxisAlignedRectangles() // the only possible transformations left to address are // square angle rotation and horizontal/vertical reflection. // // The rotation and reflection permutations total 16 but can be // reduced to 8 transformations after eliminating redundancies. // // All matrices represented here are in the form // // | xx xy | // | yx yy | // // And ignore scaling. // // Reflection is applied before rotation gfxMatrix rotation = transform * aGLWorldTransform; // Compute fuzzy zero like PreservesAxisAlignedRectangles() if (fabs(rotation.xx) < 1e-6) { if (rotation.xy < 0) { if (rotation.yx > 0) { // 90 degree rotation // // | 0 -1 | // | 1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_90; LOGD("Layer rotated 90 degrees"); } else { // Horizontal reflection then 90 degree rotation // // | 0 -1 | | -1 0 | = | 0 -1 | // | 1 0 | | 0 1 | | -1 0 | // // same as vertical reflection then 270 degree rotation // // | 0 1 | | 1 0 | = | 0 -1 | // | -1 0 | | 0 -1 | | -1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_H; LOGD("Layer vertically reflected then rotated 270 degrees"); } } else { if (rotation.yx < 0) { // 270 degree rotation // // | 0 1 | // | -1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_270; LOGD("Layer rotated 270 degrees"); } else { // Vertical reflection then 90 degree rotation // // | 0 1 | | -1 0 | = | 0 1 | // | -1 0 | | 0 1 | | 1 0 | // // Same as horizontal reflection then 270 degree rotation // // | 0 -1 | | 1 0 | = | 0 1 | // | 1 0 | | 0 -1 | | 1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_V; LOGD("Layer horizontally reflected then rotated 270 degrees"); } } } else if (rotation.xx < 0) { if (rotation.yy > 0) { // Horizontal reflection // // | -1 0 | // | 0 1 | // hwcLayer.transform = HWC_TRANSFORM_FLIP_H; LOGD("Layer rotated 180 degrees"); } else { // 180 degree rotation // // | -1 0 | // | 0 -1 | // // Same as horizontal and vertical reflection // // | -1 0 | | 1 0 | = | -1 0 | // | 0 1 | | 0 -1 | | 0 -1 | // hwcLayer.transform = HWC_TRANSFORM_ROT_180; LOGD("Layer rotated 180 degrees"); } } else { if (rotation.yy < 0) { // Vertical reflection // // | 1 0 | // | 0 -1 | // hwcLayer.transform = HWC_TRANSFORM_FLIP_V; LOGD("Layer rotated 180 degrees"); } else { // No rotation or reflection // // | 1 0 | // | 0 1 | // hwcLayer.transform = 0; } } if (state.YFlipped()) { // Invert vertical reflection flag if it was already set hwcLayer.transform ^= HWC_TRANSFORM_FLIP_V; } hwc_region_t region; if (visibleRegion.GetNumRects() > 1) { mVisibleRegions.push_back(HwcUtils::RectVector()); HwcUtils::RectVector* visibleRects = &(mVisibleRegions.back()); if(!HwcUtils::PrepareVisibleRegion(visibleRegion, transform * aGLWorldTransform, clip, bufferRect, visibleRects)) { return true; } region.numRects = visibleRects->size(); region.rects = &((*visibleRects)[0]); } else { region.numRects = 1; region.rects = &(hwcLayer.displayFrame); } hwcLayer.visibleRegionScreen = region; } else { hwcLayer.flags |= HwcUtils::HWC_COLOR_FILL; ColorLayer* colorLayer = aLayer->AsColorLayer(); if (colorLayer->GetColor().a < 1.0) { LOGD("Color layer has semitransparency which is unsupported"); return false; } hwcLayer.transform = colorLayer->GetColor().Packed(); } mHwcLayerMap.AppendElement(static_cast<LayerComposite*>(aLayer->ImplData())); mList->numHwLayers++; return true; }
bool HwcComposer2D::PrepareLayerList(Layer* aLayer, const nsIntRect& aClip, const gfxMatrix& aParentTransform, const gfxMatrix& aGLWorldTransform) { // NB: we fall off this path whenever there are container layers // that require intermediate surfaces. That means all the // GetEffective*() coordinates are relative to the framebuffer. bool fillColor = false; const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion(); if (visibleRegion.IsEmpty()) { return true; } float opacity = aLayer->GetEffectiveOpacity(); if (opacity <= 0) { LOGD("Layer is fully transparent so skip rendering"); return true; } else if (opacity < 1) { LOGD("Layer has planar semitransparency which is unsupported"); return false; } if (visibleRegion.GetNumRects() > 1) { // FIXME/bug 808339 LOGD("Layer has nontrivial visible region"); return false; } nsIntRect clip; if (!CalculateClipRect(aParentTransform * aGLWorldTransform, aLayer->GetEffectiveClipRect(), aClip, &clip)) { LOGD("Clip rect is empty. Skip layer"); return true; } gfxMatrix transform; const gfx3DMatrix& transform3D = aLayer->GetEffectiveTransform(); if (!transform3D.Is2D(&transform) || !transform.PreservesAxisAlignedRectangles()) { LOGD("Layer has a 3D transform or a non-square angle rotation"); return false; } if (ContainerLayer* container = aLayer->AsContainerLayer()) { if (container->UseIntermediateSurface()) { LOGD("Container layer needs intermediate surface"); return false; } nsAutoTArray<Layer*, 12> children; container->SortChildrenBy3DZOrder(children); for (uint32_t i = 0; i < children.Length(); i++) { if (!PrepareLayerList(children[i], clip, transform, aGLWorldTransform)) { return false; } } return true; } LayerOGL* layerGL = static_cast<LayerOGL*>(aLayer->ImplData()); LayerRenderState state = layerGL->GetRenderState(); if (!state.mSurface || state.mSurface->type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) { if (aLayer->AsColorLayer() && mColorFill) { fillColor = true; } else { LOGD("Layer doesn't have a gralloc buffer"); return false; } } if (state.BufferRotated()) { LOGD("Layer has a rotated buffer"); return false; } // OK! We can compose this layer with hwc. int current = mList ? mList->numHwLayers : 0; if (!mList || current >= mMaxLayerCount) { if (!ReallocLayerList() || current >= mMaxLayerCount) { LOGE("PrepareLayerList failed! Could not increase the maximum layer count"); return false; } } sp<GraphicBuffer> buffer = fillColor ? nullptr : GrallocBufferActor::GetFrom(*state.mSurface); nsIntRect visibleRect = visibleRegion.GetBounds(); nsIntRect bufferRect; if (fillColor) { bufferRect = nsIntRect(visibleRect); } else { if(state.mHasOwnOffset) { bufferRect = nsIntRect(state.mOffset.x, state.mOffset.y, int(buffer->getWidth()), int(buffer->getHeight())); } else { bufferRect = nsIntRect(visibleRect.x, visibleRect.y, int(buffer->getWidth()), int(buffer->getHeight())); } } hwc_layer_t& hwcLayer = mList->hwLayers[current]; if(!PrepareLayerRects(visibleRect, transform * aGLWorldTransform, clip, bufferRect, &(hwcLayer.sourceCrop), &(hwcLayer.displayFrame))) { return true; } buffer_handle_t handle = fillColor ? nullptr : buffer->getNativeBuffer()->handle; hwcLayer.handle = handle; hwcLayer.flags = 0; hwcLayer.hints = 0; hwcLayer.blending = HWC_BLENDING_NONE; hwcLayer.compositionType = HWC_USE_COPYBIT; if (!fillColor) { gfxMatrix rotation = transform * aGLWorldTransform; // Compute fuzzy equal like PreservesAxisAlignedRectangles() if (fabs(rotation.xx) < 1e-6) { if (rotation.xy < 0) { hwcLayer.transform = HWC_TRANSFORM_ROT_90; LOGD("Layer buffer rotated 90 degrees"); } else { hwcLayer.transform = HWC_TRANSFORM_ROT_270; LOGD("Layer buffer rotated 270 degrees"); } } else if (rotation.xx < 0) { hwcLayer.transform = HWC_TRANSFORM_ROT_180; LOGD("Layer buffer rotated 180 degrees"); } else { hwcLayer.transform = 0; } hwcLayer.transform |= state.YFlipped() ? HWC_TRANSFORM_FLIP_V : 0; hwc_region_t region; region.numRects = 1; region.rects = &(hwcLayer.displayFrame); hwcLayer.visibleRegionScreen = region; } else { hwcLayer.flags |= HWC_COLOR_FILL; ColorLayer* colorLayer = static_cast<ColorLayer*>(layerGL->GetLayer()); hwcLayer.transform = colorLayer->GetColor().Packed(); } mList->numHwLayers++; return true; }
bool HwcComposer2D::PrepareLayerList(Layer* aLayer, const nsIntRect& aClip, const Matrix& aParentTransform) { // NB: we fall off this path whenever there are container layers // that require intermediate surfaces. That means all the // GetEffective*() coordinates are relative to the framebuffer. bool fillColor = false; const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion(); if (visibleRegion.IsEmpty()) { return true; } uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0)); #if ANDROID_VERSION < 18 if (opacity < 0xFF) { LOGD("%s Layer has planar semitransparency which is unsupported by hwcomposer", aLayer->Name()); return false; } #endif if (aLayer->GetMaskLayer()) { LOGD("%s Layer has MaskLayer which is unsupported by hwcomposer", aLayer->Name()); return false; } nsIntRect clip; if (!HwcUtils::CalculateClipRect(aParentTransform, aLayer->GetEffectiveClipRect(), aClip, &clip)) { LOGD("%s Clip rect is empty. Skip layer", aLayer->Name()); return true; } // HWC supports only the following 2D transformations: // // Scaling via the sourceCrop and displayFrame in HwcLayer // Translation via the sourceCrop and displayFrame in HwcLayer // Rotation (in square angles only) via the HWC_TRANSFORM_ROT_* flags // Reflection (horizontal and vertical) via the HWC_TRANSFORM_FLIP_* flags // // A 2D transform with PreservesAxisAlignedRectangles() has all the attributes // above Matrix layerTransform; if (!aLayer->GetEffectiveTransform().Is2D(&layerTransform) || !layerTransform.PreservesAxisAlignedRectangles()) { LOGD("Layer EffectiveTransform has a 3D transform or a non-square angle rotation"); return false; } Matrix layerBufferTransform; if (!aLayer->GetEffectiveTransformForBuffer().Is2D(&layerBufferTransform) || !layerBufferTransform.PreservesAxisAlignedRectangles()) { LOGD("Layer EffectiveTransformForBuffer has a 3D transform or a non-square angle rotation"); return false; } if (ContainerLayer* container = aLayer->AsContainerLayer()) { if (container->UseIntermediateSurface()) { LOGD("Container layer needs intermediate surface"); return false; } nsAutoTArray<Layer*, 12> children; container->SortChildrenBy3DZOrder(children); for (uint32_t i = 0; i < children.Length(); i++) { if (!PrepareLayerList(children[i], clip, layerTransform)) { return false; } } return true; } LayerRenderState state = aLayer->GetRenderState(); if (!state.mSurface.get()) { if (aLayer->AsColorLayer() && mColorFill) { fillColor = true; } else { LOGD("%s Layer doesn't have a gralloc buffer", aLayer->Name()); return false; } } nsIntRect visibleRect = visibleRegion.GetBounds(); nsIntRect bufferRect; if (fillColor) { bufferRect = nsIntRect(visibleRect); } else { nsIntRect layerRect; if (state.mHasOwnOffset) { bufferRect = nsIntRect(state.mOffset.x, state.mOffset.y, state.mSize.width, state.mSize.height); layerRect = bufferRect; } else { //Since the buffer doesn't have its own offset, assign the whole //surface size as its buffer bounds bufferRect = nsIntRect(0, 0, state.mSize.width, state.mSize.height); layerRect = bufferRect; if (aLayer->GetType() == Layer::TYPE_IMAGE) { ImageLayer* imageLayer = static_cast<ImageLayer*>(aLayer); if(imageLayer->GetScaleMode() != ScaleMode::SCALE_NONE) { layerRect = nsIntRect(0, 0, imageLayer->GetScaleToSize().width, imageLayer->GetScaleToSize().height); } } } // In some cases the visible rect assigned to the layer can be larger // than the layer's surface, e.g., an ImageLayer with a small Image // in it. visibleRect.IntersectRect(visibleRect, layerRect); } // Buffer rotation is not to be confused with the angled rotation done by a transform matrix // It's a fancy PaintedLayer feature used for scrolling if (state.BufferRotated()) { LOGD("%s Layer has a rotated buffer", aLayer->Name()); return false; } const bool needsYFlip = state.OriginBottomLeft() ? true : false; hwc_rect_t sourceCrop, displayFrame; if(!HwcUtils::PrepareLayerRects(visibleRect, layerTransform, layerBufferTransform, clip, bufferRect, needsYFlip, &(sourceCrop), &(displayFrame))) { return true; } // OK! We can compose this layer with hwc. int current = mList ? mList->numHwLayers : 0; // Do not compose any layer below full-screen Opaque layer // Note: It can be generalized to non-fullscreen Opaque layers. bool isOpaque = opacity == 0xFF && (state.mFlags & LayerRenderStateFlags::OPAQUE); // Currently we perform opacity calculation using the *bounds* of the layer. // We can only make this assumption if we're not dealing with a complex visible region. bool isSimpleVisibleRegion = visibleRegion.Contains(visibleRect); if (current && isOpaque && isSimpleVisibleRegion) { nsIntRect displayRect = nsIntRect(displayFrame.left, displayFrame.top, displayFrame.right - displayFrame.left, displayFrame.bottom - displayFrame.top); if (displayRect.Contains(mScreenRect)) { // In z-order, all previous layers are below // the current layer. We can ignore them now. mList->numHwLayers = current = 0; mHwcLayerMap.Clear(); } } if (!mList || current >= mMaxLayerCount) { if (!ReallocLayerList() || current >= mMaxLayerCount) { LOGE("PrepareLayerList failed! Could not increase the maximum layer count"); return false; } } HwcLayer& hwcLayer = mList->hwLayers[current]; hwcLayer.displayFrame = displayFrame; setCrop(&hwcLayer, sourceCrop); buffer_handle_t handle = fillColor ? nullptr : state.mSurface->getNativeBuffer()->handle; hwcLayer.handle = handle; hwcLayer.flags = 0; hwcLayer.hints = 0; hwcLayer.blending = isOpaque ? HWC_BLENDING_NONE : HWC_BLENDING_PREMULT; #if ANDROID_VERSION >= 17 hwcLayer.compositionType = HWC_FRAMEBUFFER; hwcLayer.acquireFenceFd = -1; hwcLayer.releaseFenceFd = -1; #if ANDROID_VERSION >= 18 hwcLayer.planeAlpha = opacity; #endif #else hwcLayer.compositionType = HwcUtils::HWC_USE_COPYBIT; #endif if (!fillColor) { if (state.FormatRBSwapped()) { if (!mRBSwapSupport) { LOGD("No R/B swap support in H/W Composer"); return false; } hwcLayer.flags |= HwcUtils::HWC_FORMAT_RB_SWAP; } // Translation and scaling have been addressed in PrepareLayerRects(). // Given the above and that we checked for PreservesAxisAlignedRectangles() // the only possible transformations left to address are // square angle rotation and horizontal/vertical reflection. // // The rotation and reflection permutations total 16 but can be // reduced to 8 transformations after eliminating redundancies. // // All matrices represented here are in the form // // | xx xy | // | yx yy | // // And ignore scaling. // // Reflection is applied before rotation gfx::Matrix rotation = layerTransform; // Compute fuzzy zero like PreservesAxisAlignedRectangles() if (fabs(rotation._11) < 1e-6) { if (rotation._21 < 0) { if (rotation._12 > 0) { // 90 degree rotation // // | 0 -1 | // | 1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_90; LOGD("Layer rotated 90 degrees"); } else { // Horizontal reflection then 90 degree rotation // // | 0 -1 | | -1 0 | = | 0 -1 | // | 1 0 | | 0 1 | | -1 0 | // // same as vertical reflection then 270 degree rotation // // | 0 1 | | 1 0 | = | 0 -1 | // | -1 0 | | 0 -1 | | -1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_H; LOGD("Layer vertically reflected then rotated 270 degrees"); } } else { if (rotation._12 < 0) { // 270 degree rotation // // | 0 1 | // | -1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_270; LOGD("Layer rotated 270 degrees"); } else { // Vertical reflection then 90 degree rotation // // | 0 1 | | -1 0 | = | 0 1 | // | -1 0 | | 0 1 | | 1 0 | // // Same as horizontal reflection then 270 degree rotation // // | 0 -1 | | 1 0 | = | 0 1 | // | 1 0 | | 0 -1 | | 1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_V; LOGD("Layer horizontally reflected then rotated 270 degrees"); } } } else if (rotation._11 < 0) { if (rotation._22 > 0) { // Horizontal reflection // // | -1 0 | // | 0 1 | // hwcLayer.transform = HWC_TRANSFORM_FLIP_H; LOGD("Layer rotated 180 degrees"); } else { // 180 degree rotation // // | -1 0 | // | 0 -1 | // // Same as horizontal and vertical reflection // // | -1 0 | | 1 0 | = | -1 0 | // | 0 1 | | 0 -1 | | 0 -1 | // hwcLayer.transform = HWC_TRANSFORM_ROT_180; LOGD("Layer rotated 180 degrees"); } } else { if (rotation._22 < 0) { // Vertical reflection // // | 1 0 | // | 0 -1 | // hwcLayer.transform = HWC_TRANSFORM_FLIP_V; LOGD("Layer rotated 180 degrees"); } else { // No rotation or reflection // // | 1 0 | // | 0 1 | // hwcLayer.transform = 0; } } const bool needsYFlip = state.OriginBottomLeft() ? true : false; if (needsYFlip) { // Invert vertical reflection flag if it was already set hwcLayer.transform ^= HWC_TRANSFORM_FLIP_V; } hwc_region_t region; if (visibleRegion.GetNumRects() > 1) { mVisibleRegions.push_back(HwcUtils::RectVector()); HwcUtils::RectVector* visibleRects = &(mVisibleRegions.back()); if(!HwcUtils::PrepareVisibleRegion(visibleRegion, layerTransform, layerBufferTransform, clip, bufferRect, visibleRects)) { return true; } region.numRects = visibleRects->size(); region.rects = &((*visibleRects)[0]); } else { region.numRects = 1; region.rects = &(hwcLayer.displayFrame); } hwcLayer.visibleRegionScreen = region; } else { hwcLayer.flags |= HwcUtils::HWC_COLOR_FILL; ColorLayer* colorLayer = aLayer->AsColorLayer(); if (colorLayer->GetColor().a < 1.0) { LOGD("Color layer has semitransparency which is unsupported"); return false; } hwcLayer.transform = colorLayer->GetColor().Packed(); } mHwcLayerMap.AppendElement(static_cast<LayerComposite*>(aLayer->ImplData())); mList->numHwLayers++; return true; }