/* // Copyright (c) 2014 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ #include <HwcTrace.h> #include <DisplayPlane.h> #include <hal_public.h> #include <OMX_IVCommon.h> #include <OMX_IntelVideoExt.h> #include <PlaneCapabilities.h> #include <common/OverlayHardware.h> #include <HwcLayer.h> #include <BufferManager.h> #include <Hwcomposer.h> #define SPRITE_PLANE_MAX_STRIDE_TILED 16384 #define SPRITE_PLANE_MAX_STRIDE_LINEAR 16384 #define OVERLAY_PLANE_MAX_STRIDE_PACKED 4096 #define OVERLAY_PLANE_MAX_STRIDE_LINEAR 8192 namespace android { namespace intel { bool PlaneCapabilities::isFormatSupported(int planeType, HwcLayer *hwcLayer) { uint32_t format = hwcLayer->getFormat(); uint32_t trans = hwcLayer->getLayer()->transform; if (planeType == DisplayPlane::PLANE_SPRITE || planeType == DisplayPlane::PLANE_PRIMARY) { switch (format) { case HAL_PIXEL_FORMAT_BGRA_8888: case HAL_PIXEL_FORMAT_BGRX_8888: case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_RGB_565: return trans ? false : true; default: VTRACE("unsupported format %#x", format); return false; } } else if (planeType == DisplayPlane::PLANE_OVERLAY) { switch (format) { case HAL_PIXEL_FORMAT_I420: case HAL_PIXEL_FORMAT_YUY2: case HAL_PIXEL_FORMAT_UYVY: // TODO: overlay supports 180 degree rotation if (trans == HAL_TRANSFORM_ROT_180) { WTRACE("180 degree rotation is not supported yet"); } return trans ? false : true; case HAL_PIXEL_FORMAT_YV12: case HAL_PIXEL_FORMAT_NV12: case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: return true; default: VTRACE("unsupported format %#x", format); return false; } } else { ETRACE("invalid plane type %d", planeType); return false; } } bool PlaneCapabilities::isSizeSupported(int planeType, HwcLayer *hwcLayer) { uint32_t format = hwcLayer->getFormat(); uint32_t w = hwcLayer->getBufferWidth(); uint32_t h = hwcLayer->getBufferHeight(); const stride_t& stride = hwcLayer->getBufferStride(); bool isYUVPacked; uint32_t maxStride; if (planeType == DisplayPlane::PLANE_SPRITE || planeType == DisplayPlane::PLANE_PRIMARY) { switch (format) { case HAL_PIXEL_FORMAT_BGRA_8888: case HAL_PIXEL_FORMAT_BGRX_8888: case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_RGB_565: VTRACE("stride %d", stride.rgb.stride); if (stride.rgb.stride > SPRITE_PLANE_MAX_STRIDE_LINEAR) { VTRACE("too large stride %d", stride.rgb.stride); return false; } return true; default: VTRACE("unsupported format %#x", format); return false; } } else if (planeType == DisplayPlane::PLANE_OVERLAY) { switch (format) { case HAL_PIXEL_FORMAT_YV12: case HAL_PIXEL_FORMAT_I420: case HAL_PIXEL_FORMAT_NV12: case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: isYUVPacked = false; break; case HAL_PIXEL_FORMAT_YUY2: case HAL_PIXEL_FORMAT_UYVY: isYUVPacked = true; break; default: VTRACE("unsupported format %#x", format); return false; } // don't use overlay plane if stride is too big maxStride = OVERLAY_PLANE_MAX_STRIDE_LINEAR; if (isYUVPacked) { maxStride = OVERLAY_PLANE_MAX_STRIDE_PACKED; } if (stride.yuv.yStride > maxStride) { VTRACE("stride %d is too large", stride.yuv.yStride); return false; } hwc_frect_t& srcCrop = hwcLayer->getLayer()->sourceCropf; uint32_t width = srcCrop.right - srcCrop.left; uint32_t height = srcCrop.bottom - srcCrop.top; if (width <= 64 || height <= 64) { DTRACE("width or height of source crop is less than 64, fallback to GLES"); return false; } if ((height & 0x1) || (width & 0x1)){ if (!hwcLayer->isProtected()) { DTRACE("unprotected video content, height or width of source crop is not even, fallback to GLES "); return false; } } return true; } else { ETRACE("invalid plane type %d", planeType); return false; } } bool PlaneCapabilities::isBlendingSupported(int planeType, HwcLayer *hwcLayer) { uint32_t blending = (uint32_t)hwcLayer->getLayer()->blending; uint8_t planeAlpha = hwcLayer->getLayer()->planeAlpha; if (planeType == DisplayPlane::PLANE_SPRITE || planeType == DisplayPlane::PLANE_PRIMARY) { // support premultipled & none blanding switch (blending) { case HWC_BLENDING_NONE: case HWC_BLENDING_PREMULT: // add coverage alpha support for ann case HWC_BLENDING_COVERAGE: return true; default: VTRACE("unsupported blending %#x", blending); return false; } } else if (planeType == DisplayPlane::PLANE_OVERLAY) { // overlay doesn't support blending return (blending == HWC_BLENDING_NONE) ? true : false; } else { ETRACE("invalid plane type %d", planeType); return false; } } bool PlaneCapabilities::isScalingSupported(int planeType, HwcLayer *hwcLayer) { hwc_frect_t& src = hwcLayer->getLayer()->sourceCropf; hwc_rect_t& dest = hwcLayer->getLayer()->displayFrame; uint32_t trans = hwcLayer->getLayer()->transform; int srcW, srcH; int dstW, dstH; srcW = (int)src.right - (int)src.left; srcH = (int)src.bottom - (int)src.top; dstW = dest.right - dest.left; dstH = dest.bottom - dest.top; if (planeType == DisplayPlane::PLANE_SPRITE || planeType == DisplayPlane::PLANE_PRIMARY) { // no scaling is supported return ((srcW == dstW) && (srcH == dstH)) ? true : false; } else if (planeType == DisplayPlane::PLANE_OVERLAY) { // overlay cannot support resolution that bigger than 2047x2047. if ((srcW > INTEL_OVERLAY_MAX_WIDTH - 1) || (srcH > INTEL_OVERLAY_MAX_HEIGHT - 1)) { uint32_t format = hwcLayer->getFormat(); if (format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar || format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) { // will fall back to GLES if no scaling buffer provided by ved later // so don't return false and print a warning, it's for video format only. WTRACE("source size %dx%d hit overlay resolution limitation.", srcW, srcH); } else { return false; } } if (dstW <= 100 || dstH <= 1 || srcW <= 100 || srcH <= 1) { // Workaround: Overlay flip when height is 1 causes MIPI stall on TNG DTRACE("invalid destination size: %dx%d, fall back to GLES", dstW, dstH); return false; } if (trans == HAL_TRANSFORM_ROT_90 || trans == HAL_TRANSFORM_ROT_270) { int tmp = srcW; srcW = srcH; srcH = tmp; } if (!hwcLayer->isProtected()) { if ((int)src.left & 63) { DTRACE("offset %d is not 64 bytes aligned, fall back to GLES", (int)src.left); return false; } float scaleX = (float)srcW / dstW; float scaleY = (float)srcH / dstH; if (scaleX >= 3 || scaleY >= 3) { DTRACE("overlay rotation with scaling >= 3, fall back to GLES"); return false; } #if 0 if (trans == HAL_TRANSFORM_ROT_90 && (float)srcW / srcH != (float)dstW / dstH) { // FIXME: work aournd for pipe crashing issue, when rotate screen // from 90 to 0 degree (with Sharp 25x16 panel). DTRACE("overlay rotation with uneven scaling, fall back to GLES"); return false; } #endif } return true; } else { ETRACE("invalid plane type %d", planeType); return false; } } bool PlaneCapabilities::isTransformSupported(int planeType, HwcLayer *hwcLayer) { uint32_t trans = hwcLayer->getLayer()->transform; if (planeType == DisplayPlane::PLANE_OVERLAY) { // overlay does not support FLIP_H/FLIP_V switch (trans) { case 0: case HAL_TRANSFORM_ROT_90: case HAL_TRANSFORM_ROT_180: case HAL_TRANSFORM_ROT_270: return true; default: return false; } } // don't transform any tranform return trans ? false : true; } } // namespace intel } // namespace android