/* // 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 <math.h> #include <HwcTrace.h> #include <Drm.h> #include <Hwcomposer.h> #include <anniedale/AnnOverlayPlane.h> #include <tangier/TngGrallocBuffer.h> // FIXME: remove it #include <OMX_IVCommon.h> #include <OMX_IntelVideoExt.h> namespace android { namespace intel { AnnOverlayPlane::AnnOverlayPlane(int index, int disp) : OverlayPlaneBase(index, disp), mRotationBufProvider(NULL), mRotationConfig(0), mZOrderConfig(0), mUseOverlayRotation(true) { CTRACE(); memset(&mContext, 0, sizeof(mContext)); } AnnOverlayPlane::~AnnOverlayPlane() { CTRACE(); } void AnnOverlayPlane::setZOrderConfig(ZOrderConfig& zorderConfig, void *nativeConfig) { long slot = (long)nativeConfig; CTRACE(); switch (slot) { case 0: mZOrderConfig = 0; break; case 1: mZOrderConfig = (1 << 8); break; case 2: mZOrderConfig = (2 << 8); break; case 3: mZOrderConfig = (3 << 8); break; default: ETRACE("Invalid overlay plane zorder %ld", slot); return; } } bool AnnOverlayPlane::reset() { OverlayPlaneBase::reset(); if (mRotationBufProvider) { mRotationBufProvider->reset(); } return true; } bool AnnOverlayPlane::enable() { RETURN_FALSE_IF_NOT_INIT(); // by default always use overlay rotation mUseOverlayRotation = true; if (mContext.ctx.ov_ctx.ovadd & (0x1 << 15)) return true; mContext.ctx.ov_ctx.ovadd |= (0x1 << 15); // flush flush(PLANE_ENABLE); return true; } bool AnnOverlayPlane::disable() { RETURN_FALSE_IF_NOT_INIT(); if (!(mContext.ctx.ov_ctx.ovadd & (0x1 << 15))) return true; mContext.ctx.ov_ctx.ovadd &= ~(0x1 << 15); mContext.ctx.ov_ctx.ovadd &= ~(0x300); mContext.ctx.ov_ctx.ovadd |= mPipeConfig; // flush flush(PLANE_DISABLE); return true; } void AnnOverlayPlane::postFlip() { // when using AnnOverlayPlane through AnnDisplayPlane as proxy, postFlip is never // called so mUpdateMasks is never reset. // When using AnnOverlayPlane directly, postFlip is invoked and mUpdateMasks is reset // post-flip. // need to check why mUpdateMasks = 0 causes video freeze. //DisplayPlane::postFlip(); } void AnnOverlayPlane::resetBackBuffer(int buf) { CTRACE(); if (!mBackBuffer[buf] || !mBackBuffer[buf]->buf) return; OverlayBackBufferBlk *backBuffer = mBackBuffer[buf]->buf; memset(backBuffer, 0, sizeof(OverlayBackBufferBlk)); // reset overlay backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) | (OVERLAY_INIT_BRIGHTNESS & 0xff); backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION; backBuffer->DCLRKV = OVERLAY_INIT_COLORKEY; backBuffer->DCLRKM = OVERLAY_INIT_COLORKEYMASK; backBuffer->OCONFIG = 0; backBuffer->OCONFIG |= (0x1 << 27); // use 3 line buffers backBuffer->OCONFIG |= 0x1; backBuffer->SCHRKEN &= ~(0x7 << 24); backBuffer->SCHRKEN |= 0xff; } bool AnnOverlayPlane::bufferOffsetSetup(BufferMapper& mapper) { CTRACE(); OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; if (!backBuffer) { ETRACE("invalid back buffer"); return false; } uint32_t format = mapper.getFormat(); uint32_t gttOffsetInBytes = (mapper.getGttOffsetInPage(0) << 12); uint32_t yStride = mapper.getStride().yuv.yStride; uint32_t uvStride = mapper.getStride().yuv.uvStride; uint32_t w = mapper.getWidth(); uint32_t h = mapper.getHeight(); uint32_t srcX= mapper.getCrop().x; uint32_t srcY= mapper.getCrop().y; uint32_t ySurface, uSurface, vSurface; uint32_t yTileOffsetX, yTileOffsetY; uint32_t uTileOffsetX, uTileOffsetY; uint32_t vTileOffsetX, vTileOffsetY; // clear original format setting backBuffer->OCMD &= ~(0xf << 10); backBuffer->OCMD &= ~OVERLAY_MEMORY_LAYOUT_TILED; backBuffer->OBUF_0Y = 0; backBuffer->OBUF_0V = 0; backBuffer->OBUF_0U = 0; // Y/U/V plane must be 4k bytes aligned. ySurface = gttOffsetInBytes; if (mIsProtectedBuffer) { // temporary workaround until vsync event logic is corrected. // it seems that overlay buffer update and renderring can be overlapped, // as such encryption bit may be cleared during HW rendering ySurface |= 0x01; } switch(format) { case HAL_PIXEL_FORMAT_YV12: // YV12 vSurface = ySurface + yStride * h; uSurface = vSurface + uvStride * (h / 2); yTileOffsetX = srcX; yTileOffsetY = srcY; uTileOffsetX = srcX / 2; uTileOffsetY = srcY / 2; vTileOffsetX = uTileOffsetX; vTileOffsetY = uTileOffsetY; backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420; break; case HAL_PIXEL_FORMAT_I420: // I420 uSurface = ySurface + yStride * h; vSurface = uSurface + uvStride * (h / 2); yTileOffsetX = srcX; yTileOffsetY = srcY; uTileOffsetX = srcX / 2; uTileOffsetY = srcY / 2; vTileOffsetX = uTileOffsetX; vTileOffsetY = uTileOffsetY; backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420; break; case HAL_PIXEL_FORMAT_NV12: // NV12 uSurface = ySurface; vSurface = ySurface; backBuffer->OBUF_0U = yStride * h; yTileOffsetX = srcX; yTileOffsetY = srcY; uTileOffsetX = srcX / 2; uTileOffsetY = srcY / 2 + h; vTileOffsetX = uTileOffsetX; vTileOffsetY = uTileOffsetY; backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; break; // NOTE: this is the decoded video format, align the height to 32B //as it's defined by video driver case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: // NV12 uSurface = ySurface + yStride * align_to(h, 32); vSurface = ySurface + yStride * align_to(h, 32); yTileOffsetX = srcX; yTileOffsetY = srcY; uTileOffsetX = srcX; uTileOffsetY = srcY / 2; vTileOffsetX = uTileOffsetX; vTileOffsetY = uTileOffsetY; backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; break; case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: //NV12_tiled uSurface = ySurface + yStride * align_to(h, 32); vSurface = ySurface + yStride * align_to(h, 32); yTileOffsetX = srcX; yTileOffsetY = srcY; uTileOffsetX = srcX; uTileOffsetY = srcY / 2; vTileOffsetX = uTileOffsetX; vTileOffsetY = uTileOffsetY; backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; backBuffer->OCMD |= OVERLAY_MEMORY_LAYOUT_TILED; break; case HAL_PIXEL_FORMAT_YUY2: // YUY2 uSurface = ySurface; vSurface = ySurface; yTileOffsetX = srcX; yTileOffsetY = srcY; uTileOffsetX = yTileOffsetX; uTileOffsetY = yTileOffsetY; vTileOffsetX = yTileOffsetX; vTileOffsetY = yTileOffsetY; backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422; backBuffer->OCMD |= OVERLAY_PACKED_ORDER_YUY2; break; case HAL_PIXEL_FORMAT_UYVY: // UYVY uSurface = ySurface; vSurface = ySurface; yTileOffsetX = srcX; yTileOffsetY = srcY; uTileOffsetX = yTileOffsetX; uTileOffsetY = yTileOffsetY; vTileOffsetX = yTileOffsetX; vTileOffsetY = yTileOffsetY; backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422; backBuffer->OCMD |= OVERLAY_PACKED_ORDER_UYVY; break; default: ETRACE("unsupported format %d", format); return false; } backBuffer->OSTART_0Y = ySurface; backBuffer->OSTART_0U = uSurface; backBuffer->OSTART_0V = vSurface; backBuffer->OBUF_0Y += srcY * yStride + srcX; backBuffer->OBUF_0V += (srcY / 2) * uvStride + srcX; backBuffer->OBUF_0U += (srcY / 2) * uvStride + srcX; backBuffer->OTILEOFF_0Y = yTileOffsetY << 16 | yTileOffsetX; backBuffer->OTILEOFF_0U = uTileOffsetY << 16 | uTileOffsetX; backBuffer->OTILEOFF_0V = vTileOffsetY << 16 | vTileOffsetX; VTRACE("done. offset (%d, %d, %d)", backBuffer->OBUF_0Y, backBuffer->OBUF_0U, backBuffer->OBUF_0V); return true; } bool AnnOverlayPlane::scalingSetup(BufferMapper& mapper) { int xscaleInt, xscaleFract, yscaleInt, yscaleFract; int xscaleIntUV, xscaleFractUV; int yscaleIntUV, yscaleFractUV; // UV is half the size of Y -- YUV420 int uvratio = 2; uint32_t newval; coeffRec xcoeffY[N_HORIZ_Y_TAPS * N_PHASES]; coeffRec xcoeffUV[N_HORIZ_UV_TAPS * N_PHASES]; coeffRec ycoeffY[N_VERT_Y_TAPS * N_PHASES]; coeffRec ycoeffUV[N_VERT_UV_TAPS * N_PHASES]; int i, j, pos; bool scaleChanged = false; int x, y, w, h; int deinterlace_factor = 1; drmModeModeInfoPtr mode = &mModeInfo; OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; if (!backBuffer) { ETRACE("invalid back buffer"); return false; } if (mPanelOrientation == PANEL_ORIENTATION_180) { if (mode->hdisplay) x = mode->hdisplay - mPosition.x - mPosition.w; else x = mPosition.x; if (mode->vdisplay) y = mode->vdisplay - mPosition.y - mPosition.h; else y = mPosition.y; } else { x = mPosition.x; y = mPosition.y; } w = mPosition.w; h = mPosition.h; // check position checkPosition(x, y, w, h); VTRACE("final position (%d, %d, %d, %d)", x, y, w, h); if ((w <= 0) || (h <= 0)) { ETRACE("invalid dst width/height"); return false; } // setup dst position backBuffer->DWINPOS = (y << 16) | x; backBuffer->DWINSZ = (h << 16) | w; uint32_t srcWidth = mapper.getCrop().w; uint32_t srcHeight = mapper.getCrop().h; uint32_t dstWidth = w; uint32_t dstHeight = h; if (mBobDeinterlace && !mTransform) deinterlace_factor = 2; VTRACE("src (%dx%d), dst (%dx%d), transform %d", srcWidth, srcHeight, dstWidth, dstHeight, mTransform); // switch destination width/height for scale factor calculation // for 90/270 transformation if (mUseOverlayRotation && ((mTransform == HWC_TRANSFORM_ROT_90) || (mTransform == HWC_TRANSFORM_ROT_270))) { uint32_t tmp = srcHeight; srcHeight = srcWidth; srcWidth = tmp; } // Y down-scale factor as a multiple of 4096 if (srcWidth == dstWidth && srcHeight == dstHeight) { xscaleFract = (1 << 12); yscaleFract = (1 << 12) / deinterlace_factor; } else { xscaleFract = ((srcWidth - 1) << 12) / dstWidth; yscaleFract = ((srcHeight - 1) << 12) / (dstHeight * deinterlace_factor); } // Calculate the UV scaling factor xscaleFractUV = xscaleFract / uvratio; yscaleFractUV = yscaleFract / uvratio; // To keep the relative Y and UV ratios exact, round the Y scales // to a multiple of the Y/UV ratio. xscaleFract = xscaleFractUV * uvratio; yscaleFract = yscaleFractUV * uvratio; // Integer (un-multiplied) values xscaleInt = xscaleFract >> 12; yscaleInt = yscaleFract >> 12; xscaleIntUV = xscaleFractUV >> 12; yscaleIntUV = yscaleFractUV >> 12; // Check scaling ratio if (xscaleInt > INTEL_OVERLAY_MAX_SCALING_RATIO) { ETRACE("xscaleInt > %d", INTEL_OVERLAY_MAX_SCALING_RATIO); return false; } // shouldn't get here if (xscaleIntUV > INTEL_OVERLAY_MAX_SCALING_RATIO) { ETRACE("xscaleIntUV > %d", INTEL_OVERLAY_MAX_SCALING_RATIO); return false; } newval = (xscaleInt << 15) | ((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20); if (newval != backBuffer->YRGBSCALE) { scaleChanged = true; backBuffer->YRGBSCALE = newval; } newval = (xscaleIntUV << 15) | ((xscaleFractUV & 0xFFF) << 3) | ((yscaleFractUV & 0xFFF) << 20); if (newval != backBuffer->UVSCALE) { scaleChanged = true; backBuffer->UVSCALE = newval; } newval = yscaleInt << 16 | yscaleIntUV; if (newval != backBuffer->UVSCALEV) { scaleChanged = true; backBuffer->UVSCALEV = newval; } // Recalculate coefficients if the scaling changed // Only Horizontal coefficients so far. if (scaleChanged) { double fHCutoffY; double fHCutoffUV; double fVCutoffY; double fVCutoffUV; fHCutoffY = xscaleFract / 4096.0; fHCutoffUV = xscaleFractUV / 4096.0; fVCutoffY = yscaleFract / 4096.0; fVCutoffUV = yscaleFractUV / 4096.0; // Limit to between 1.0 and 3.0 if (fHCutoffY < MIN_CUTOFF_FREQ) fHCutoffY = MIN_CUTOFF_FREQ; if (fHCutoffY > MAX_CUTOFF_FREQ) fHCutoffY = MAX_CUTOFF_FREQ; if (fHCutoffUV < MIN_CUTOFF_FREQ) fHCutoffUV = MIN_CUTOFF_FREQ; if (fHCutoffUV > MAX_CUTOFF_FREQ) fHCutoffUV = MAX_CUTOFF_FREQ; if (fVCutoffY < MIN_CUTOFF_FREQ) fVCutoffY = MIN_CUTOFF_FREQ; if (fVCutoffY > MAX_CUTOFF_FREQ) fVCutoffY = MAX_CUTOFF_FREQ; if (fVCutoffUV < MIN_CUTOFF_FREQ) fVCutoffUV = MIN_CUTOFF_FREQ; if (fVCutoffUV > MAX_CUTOFF_FREQ) fVCutoffUV = MAX_CUTOFF_FREQ; updateCoeff(N_HORIZ_Y_TAPS, fHCutoffY, true, true, xcoeffY); updateCoeff(N_HORIZ_UV_TAPS, fHCutoffUV, true, false, xcoeffUV); updateCoeff(N_VERT_Y_TAPS, fVCutoffY, false, true, ycoeffY); updateCoeff(N_VERT_UV_TAPS, fVCutoffUV, false, false, ycoeffUV); for (i = 0; i < N_PHASES; i++) { for (j = 0; j < N_HORIZ_Y_TAPS; j++) { pos = i * N_HORIZ_Y_TAPS + j; backBuffer->Y_HCOEFS[pos] = (xcoeffY[pos].sign << 15 | xcoeffY[pos].exponent << 12 | xcoeffY[pos].mantissa); } } for (i = 0; i < N_PHASES; i++) { for (j = 0; j < N_HORIZ_UV_TAPS; j++) { pos = i * N_HORIZ_UV_TAPS + j; backBuffer->UV_HCOEFS[pos] = (xcoeffUV[pos].sign << 15 | xcoeffUV[pos].exponent << 12 | xcoeffUV[pos].mantissa); } } for (i = 0; i < N_PHASES; i++) { for (j = 0; j < N_VERT_Y_TAPS; j++) { pos = i * N_VERT_Y_TAPS + j; backBuffer->Y_VCOEFS[pos] = (ycoeffY[pos].sign << 15 | ycoeffY[pos].exponent << 12 | ycoeffY[pos].mantissa); } } for (i = 0; i < N_PHASES; i++) { for (j = 0; j < N_VERT_UV_TAPS; j++) { pos = i * N_VERT_UV_TAPS + j; backBuffer->UV_VCOEFS[pos] = (ycoeffUV[pos].sign << 15 | ycoeffUV[pos].exponent << 12 | ycoeffUV[pos].mantissa); } } } XTRACE(); return true; } void AnnOverlayPlane::setTransform(int transform) { RETURN_VOID_IF_NOT_INIT(); if (mPanelOrientation == PANEL_ORIENTATION_180) transform ^= HWC_TRANSFORM_ROT_180; DisplayPlane::setTransform(transform); // setup transform config switch (mTransform) { case HWC_TRANSFORM_ROT_90: mRotationConfig = (0x1 << 10); break; case HWC_TRANSFORM_ROT_180: mRotationConfig = (0x2 << 10); break; case HWC_TRANSFORM_ROT_270: mRotationConfig = (0x3 << 10); break; case 0: mRotationConfig = 0; break; default: ETRACE("Invalid transform %d", mTransform); mRotationConfig = 0; break; } } // HSD 4645510: // This is a SOC limition, that when source buffer width range is // in (960, 1024] - one cache line length, and rotation bit is set // in portrait mode, video will show distortion. bool AnnOverlayPlane::isSettingRotBitAllowed() { uint32_t width = mSrcCrop.w; if ((width > 960 && width <= 1024) && (mTransform == 0 || mTransform == HAL_TRANSFORM_ROT_180)) return false; return true; } bool AnnOverlayPlane::flip(void *ctx) { uint32_t ovadd = 0; RETURN_FALSE_IF_NOT_INIT(); if (!DisplayPlane::flip(ctx)) { ETRACE("failed to flip display plane."); return false; } // update back buffer address ovadd = (mBackBuffer[mCurrent]->gttOffsetInPage << 12); // enable rotation mode and setup rotation config // if video is interlaced, cannot use overlay rotation if (mIndex == 0 && !mBobDeinterlace) { if (isSettingRotBitAllowed()) ovadd |= (1 << 12); ovadd |= mRotationConfig; } // setup z-order config ovadd |= mZOrderConfig; // load coefficients ovadd |= 0x1; // enable overlay ovadd |= (1 << 15); mContext.type = DC_OVERLAY_PLANE; mContext.ctx.ov_ctx.ovadd = ovadd; mContext.ctx.ov_ctx.index = mIndex; mContext.ctx.ov_ctx.pipe = mDevice; mContext.ctx.ov_ctx.ovadd |= mPipeConfig; // move to next back buffer mCurrent = (mCurrent + 1) % OVERLAY_BACK_BUFFER_COUNT; VTRACE("ovadd = %#x, index = %d, device = %d", mContext.ctx.ov_ctx.ovadd, mIndex, mDevice); return true; } void* AnnOverlayPlane::getContext() const { CTRACE(); return (void *)&mContext; } bool AnnOverlayPlane::setDataBuffer(BufferMapper& mapper) { if (OverlayPlaneBase::setDataBuffer(mapper) == false) { return false; } signalVideoRotation(mapper); if (mIsProtectedBuffer) { // Bit 0: Decryption request, only allowed to change on a synchronous flip // This request will be qualified with the separate decryption enable bit for OV mBackBuffer[mCurrent]->buf->OSTART_0Y |= 0x1; mBackBuffer[mCurrent]->buf->OSTART_1Y |= 0x1; } mContext.gtt_key = (unsigned long)mapper.getCpuAddress(0); return true; } bool AnnOverlayPlane::initialize(uint32_t bufferCount) { if (!OverlayPlaneBase::initialize(bufferCount)) { ETRACE("failed to initialize OverlayPlaneBase"); return false; } // setup rotation buffer mRotationBufProvider = new RotationBufferProvider(mWsbm); if (!mRotationBufProvider || !mRotationBufProvider->initialize()) { DEINIT_AND_RETURN_FALSE("failed to initialize RotationBufferProvider"); } return true; } void AnnOverlayPlane::deinitialize() { DEINIT_AND_DELETE_OBJ(mRotationBufProvider); OverlayPlaneBase::deinitialize(); } bool AnnOverlayPlane::rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper) { struct VideoPayloadBuffer *payload; uint32_t format; // only NV12_VED has rotated buffer format = mapper.getFormat(); if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar && format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) { ETRACE("invalid video format %#x", format); return false; } payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1); // check payload if (!payload) { ETRACE("no payload found"); return false; } if (payload->force_output_method == FORCE_OUTPUT_GPU) { ETRACE("Output method is not supported!"); return false; } if (payload->client_transform != mTransform || mBobDeinterlace) { if (!mRotationBufProvider->setupRotationBuffer(payload, mTransform)) { DTRACE("failed to setup rotation buffer"); return false; } } rotatedMapper = getTTMMapper(mapper, payload); return true; } void AnnOverlayPlane::signalVideoRotation(BufferMapper& mapper) { struct VideoPayloadBuffer *payload; uint32_t format; // check if it's video layer format = mapper.getFormat(); if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar && format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) { return; } payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1); if (!payload) { ETRACE("no payload found"); return; } /* if use overlay rotation, signal decoder to stop rotation */ if (mUseOverlayRotation) { if (payload->client_transform) { WTRACE("signal decoder to stop generate rotation buffer"); payload->hwc_timestamp = systemTime(); payload->layer_transform = 0; } } else { /* if overlay rotation cannot be used, signal decoder to start rotation */ if (payload->client_transform != mTransform) { WTRACE("signal decoder to generate rotation buffer with transform %d", mTransform); payload->hwc_timestamp = systemTime(); payload->layer_transform = mTransform; } } } bool AnnOverlayPlane::useOverlayRotation(BufferMapper& mapper) { if (mTransform == 0) return true; if (!isSettingRotBitAllowed()) { mUseOverlayRotation = false; mRotationConfig = 0; return false; } // workaround limitation of overlay rotation by falling back to use VA rotated buffer bool fallback = false; float scaleX = (float)mSrcCrop.w / mPosition.w; float scaleY = (float)mSrcCrop.h / mPosition.h; if (mTransform == HAL_TRANSFORM_ROT_270 || mTransform == HAL_TRANSFORM_ROT_90) { scaleX = (float)mSrcCrop.w / mPosition.h; scaleY = (float)mSrcCrop.h / mPosition.w; } if (scaleX >= 3 || scaleY >= 3) { if (mUseOverlayRotation) { DTRACE("overlay rotation with scaling >= 3, use VA rotated buffer"); } fallback = true; } else if ((int)mSrcCrop.x & 63) { if (mUseOverlayRotation) { DTRACE("offset is not 64 bytes aligned, use VA rotated buffer"); } fallback = true; } #if 0 else if (mTransform != HAL_TRANSFORM_ROT_180 && scaleX != scaleY) { if (mUseOverlayRotation) { DTRACE("overlay rotation with uneven scaling, use VA rotated buffer"); } fallback = true; } #endif // per DC spec, if video is 1080(H)x1920(V), the buffer // need 1920 of 64-pixel strip if using hw rotation. // fallback to video ration buffer in such case. if (mSrcCrop.w == 1080 && mSrcCrop.h == 1920 && mTransform != 0) { DTRACE("1080(H)x1920(V) cannot use hw rotation, use VA rotated buffer"); fallback = true; } if (fallback || mBobDeinterlace) { mUseOverlayRotation = false; mRotationConfig = 0; } else { mUseOverlayRotation = true; } return mUseOverlayRotation; } bool AnnOverlayPlane::scaledBufferReady(BufferMapper& mapper, BufferMapper* &scaledMapper, VideoPayloadBuffer *payload) { mUseScaledBuffer = (payload->scaling_khandle != 0); if (mUseScaledBuffer) { mapper.setCrop(mapper.getCrop().x, mapper.getCrop().y, payload->scaling_width, payload->scaling_height); scaledMapper = getTTMMapper(mapper, payload); return (scaledMapper != 0); } return mUseScaledBuffer; } bool AnnOverlayPlane::flush(uint32_t flags) { RETURN_FALSE_IF_NOT_INIT(); ATRACE("flags = %#x, type = %d, index = %d", flags, mType, mIndex); if (!(flags & PLANE_ENABLE) && !(flags & PLANE_DISABLE)) { ETRACE("invalid flush flags."); return false; } struct drm_psb_register_rw_arg arg; memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); if (flags & PLANE_DISABLE) arg.plane_disable_mask = 1; else if (flags & PLANE_ENABLE) arg.plane_enable_mask = 1; arg.plane.type = DC_OVERLAY_PLANE; arg.plane.index = mIndex; arg.plane.ctx = mContext.ctx.ov_ctx.ovadd; if (flags & PLANE_DISABLE) { DTRACE("disabling overlay %d on device %d", mIndex, mDevice); } // issue ioctl Drm *drm = Hwcomposer::getInstance().getDrm(); bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); if (ret == false) { WTRACE("overlay update failed with error code %d", ret); return false; } return true; } } // namespace intel } // namespace android