diff options
Diffstat (limited to 'merrifield/ips')
71 files changed, 10007 insertions, 0 deletions
diff --git a/merrifield/ips/anniedale/AnnCursorPlane.cpp b/merrifield/ips/anniedale/AnnCursorPlane.cpp new file mode 100644 index 0000000..c6607dd --- /dev/null +++ b/merrifield/ips/anniedale/AnnCursorPlane.cpp @@ -0,0 +1,223 @@ +/* +// 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 <Hwcomposer.h> +#include <BufferManager.h> +#include <anniedale/AnnCursorPlane.h> +#include <tangier/TngGrallocBuffer.h> +#include <hal_public.h> + +namespace android { +namespace intel { + +AnnCursorPlane::AnnCursorPlane(int index, int disp) + : DisplayPlane(index, PLANE_CURSOR, disp) +{ + CTRACE(); + memset(&mContext, 0, sizeof(mContext)); + memset(&mCrop, 0, sizeof(mCrop)); +} + +AnnCursorPlane::~AnnCursorPlane() +{ + CTRACE(); +} + +bool AnnCursorPlane::enable() +{ + return enablePlane(true); + +} + +bool AnnCursorPlane::disable() +{ + return enablePlane(false); +} + +bool AnnCursorPlane::reset() +{ + // clear mCrop once reset + memset(&mCrop, 0, sizeof(mCrop)); + return true; +} + +void* AnnCursorPlane::getContext() const +{ + CTRACE(); + return (void *)&mContext; +} + +void AnnCursorPlane::setZOrderConfig(ZOrderConfig& config, void *nativeConfig) +{ + (void) config; + (void) nativeConfig; + + CTRACE(); +} + +bool AnnCursorPlane::setDataBuffer(buffer_handle_t handle) +{ + bool ret; + + if (!handle) { + ETRACE("handle is NULL"); + return false; + } + + ret = DisplayPlane::setDataBuffer(handle); + if (ret == false) { + ETRACE("failed to set data buffer"); + return ret; + } + + return true; +} + +bool AnnCursorPlane::setDataBuffer(BufferMapper& mapper) +{ + int w = mapper.getWidth(); + int h = mapper.getHeight(); + int cursorSize = 0; + + CTRACE(); + + // setup plane position + int dstX = mPosition.x; + int dstY = mPosition.y; + + if (h < w) { + cursorSize = h; + } else { + cursorSize = w; + } + + uint32_t cntr = 0; + if (64 <= cursorSize && cursorSize < 128) { + cursorSize = 64; + cntr = 0x7; + } else if (128 <= cursorSize && cursorSize < 256) { + cursorSize = 128; + cntr = 0x2; + } else { + cursorSize = 256; + cntr = 0x3; + } + + if (mapper.getFormat() == HAL_PIXEL_FORMAT_RGBA_8888) { + cntr |= 1 << 5; + } else if (mapper.getFormat() == HAL_PIXEL_FORMAT_BGRA_8888) { + // swap color from BGRA to RGBA - alpha is MSB + uint8_t *p = (uint8_t *)(mapper.getCpuAddress(0)); + uint8_t *srcPixel; + uint32_t stride = mapper.getStride().rgb.stride; + uint8_t temp; + if (!p) { + return false; + } + + for (int i = 0; i < cursorSize; i++) { + for (int j = 0; j < cursorSize; j++) { + srcPixel = p + i*stride + j*4; + temp = srcPixel[0]; + srcPixel[0] = srcPixel[2]; + srcPixel[2] = temp; + } + } + cntr |= 1 << 5; + } else { + ETRACE("invalid color format"); + return false; + } + + // update context + mContext.type = DC_CURSOR_PLANE; + mContext.ctx.cs_ctx.index = mIndex; + mContext.ctx.cs_ctx.pipe = mDevice; + mContext.ctx.cs_ctx.cntr = cntr; + mContext.ctx.cs_ctx.surf = mapper.getGttOffsetInPage(0) << 12; + + mContext.ctx.cs_ctx.pos = 0; + if (dstX < 0) { + mContext.ctx.cs_ctx.pos |= 1 << 15; + dstX = -dstX; + } + if (dstY < 0) { + mContext.ctx.cs_ctx.pos |= 1 << 31; + dstY = -dstY; + } + mContext.ctx.cs_ctx.pos |= (dstY & 0xfff) << 16 | (dstX & 0xfff); + return true; +} + +bool AnnCursorPlane::enablePlane(bool enabled) +{ + RETURN_FALSE_IF_NOT_INIT(); + + struct drm_psb_register_rw_arg arg; + memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); + if (enabled) { + arg.plane_enable_mask = 1; + } else { + arg.plane_disable_mask = 1; + } + + arg.plane.type = DC_CURSOR_PLANE; + arg.plane.index = mIndex; + arg.plane.ctx = 0; + + // issue ioctl + Drm *drm = Hwcomposer::getInstance().getDrm(); + bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); + if (ret == false) { + WTRACE("plane enabling (%d) failed with error code %d", enabled, ret); + return false; + } + + return true; +} + +bool AnnCursorPlane::isDisabled() +{ + RETURN_FALSE_IF_NOT_INIT(); + + struct drm_psb_register_rw_arg arg; + memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); + + arg.plane.type = DC_CURSOR_PLANE; + arg.get_plane_state_mask = 1; + arg.plane.index = mIndex; + arg.plane.ctx = 0; + + // issue ioctl + Drm *drm = Hwcomposer::getInstance().getDrm(); + bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); + if (ret == false) { + WTRACE("plane state query failed with error code %d", ret); + return false; + } + + return arg.plane.ctx == PSB_DC_PLANE_DISABLED; +} + +void AnnCursorPlane::postFlip() +{ + // prevent mUpdateMasks from being reset + // skipping flip may cause flicking +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/anniedale/AnnCursorPlane.h b/merrifield/ips/anniedale/AnnCursorPlane.h new file mode 100644 index 0000000..88d8075 --- /dev/null +++ b/merrifield/ips/anniedale/AnnCursorPlane.h @@ -0,0 +1,59 @@ +/* +// 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. +*/ + +#ifndef ANN_CUR_PLANE_H +#define ANN_CUR_PLANE_H + +#include <utils/KeyedVector.h> +#include <hal_public.h> +#include <Hwcomposer.h> +#include <BufferCache.h> +#include <DisplayPlane.h> + +#include <linux/psb_drm.h> + +namespace android { +namespace intel { + +class AnnCursorPlane : public DisplayPlane { +public: + AnnCursorPlane(int index, int disp); + virtual ~AnnCursorPlane(); +public: + // hardware operations + bool enable(); + bool disable(); + bool reset(); + bool isDisabled(); + void postFlip(); + + void* getContext() const; + void setZOrderConfig(ZOrderConfig& config, void *nativeConfig); + + bool setDataBuffer(buffer_handle_t handle); +protected: + bool setDataBuffer(BufferMapper& mapper); + bool enablePlane(bool enabled); + +protected: + struct intel_dc_plane_ctx mContext; + crop_t mCrop; +}; + +} // namespace intel +} // namespace android + +#endif /* ANN_CUR_PLANE_H */ diff --git a/merrifield/ips/anniedale/AnnOverlayPlane.cpp b/merrifield/ips/anniedale/AnnOverlayPlane.cpp new file mode 100644 index 0000000..930f895 --- /dev/null +++ b/merrifield/ips/anniedale/AnnOverlayPlane.cpp @@ -0,0 +1,834 @@ +/* +// 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 diff --git a/merrifield/ips/anniedale/AnnOverlayPlane.h b/merrifield/ips/anniedale/AnnOverlayPlane.h new file mode 100644 index 0000000..3cea338 --- /dev/null +++ b/merrifield/ips/anniedale/AnnOverlayPlane.h @@ -0,0 +1,78 @@ +/* +// 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. +*/ +#ifndef ANN_OVERLAY_PLANE_H +#define ANN_OVERLAY_PLANE_H + +#include <utils/KeyedVector.h> +#include <hal_public.h> +#include <DisplayPlane.h> +#include <BufferMapper.h> +#include <common/Wsbm.h> +#include <common/OverlayPlaneBase.h> +#include <common/RotationBufferProvider.h> + +namespace android { +namespace intel { + +class AnnOverlayPlane : public OverlayPlaneBase { +public: + AnnOverlayPlane(int index, int disp); + virtual ~AnnOverlayPlane(); + + virtual void setTransform(int transform); + virtual void setZOrderConfig(ZOrderConfig& config, void *nativeConfig); + + // plane operations + virtual bool flip(void *ctx); + virtual bool reset(); + virtual bool enable(); + virtual bool disable(); + virtual void postFlip(); + virtual void* getContext() const; + virtual bool initialize(uint32_t bufferCount); + virtual void deinitialize(); + virtual bool rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper); + virtual bool useOverlayRotation(BufferMapper& mapper); + virtual bool scaledBufferReady(BufferMapper& mapper, BufferMapper* &scaledMapper, VideoPayloadBuffer *payload); + +private: + void signalVideoRotation(BufferMapper& mapper); + bool isSettingRotBitAllowed(); + +protected: + virtual bool setDataBuffer(BufferMapper& mapper); + virtual bool flush(uint32_t flags); + virtual bool bufferOffsetSetup(BufferMapper& mapper); + virtual bool scalingSetup(BufferMapper& mapper); + + virtual void resetBackBuffer(int buf); + + RotationBufferProvider *mRotationBufProvider; + + // rotation config + uint32_t mRotationConfig; + // z order config + uint32_t mZOrderConfig; + bool mUseOverlayRotation; + // hardware context + struct intel_dc_plane_ctx mContext; +}; + +} // namespace intel +} // namespace android + +#endif /* ANN_OVERLAY_PLANE_H */ + diff --git a/merrifield/ips/anniedale/AnnPlaneManager.cpp b/merrifield/ips/anniedale/AnnPlaneManager.cpp new file mode 100644 index 0000000..b20f851 --- /dev/null +++ b/merrifield/ips/anniedale/AnnPlaneManager.cpp @@ -0,0 +1,461 @@ +/* +// 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 <utils/String8.h> +#include <anniedale/AnnPlaneManager.h> +#include <anniedale/AnnRGBPlane.h> +#include <anniedale/AnnOverlayPlane.h> +#include <anniedale/AnnCursorPlane.h> +#include <PlaneCapabilities.h> + +namespace android { +namespace intel { + + +struct PlaneDescription { + char nickname; + int type; + int index; +}; + + +static PlaneDescription PLANE_DESC[] = +{ + // nickname must be continous and start with 'A', + // it is used to fast locate plane index and type + {'A', DisplayPlane::PLANE_PRIMARY, 0}, + {'B', DisplayPlane::PLANE_PRIMARY, 1}, + {'C', DisplayPlane::PLANE_PRIMARY, 2}, + {'D', DisplayPlane::PLANE_SPRITE, 0}, + {'E', DisplayPlane::PLANE_SPRITE, 1}, + {'F', DisplayPlane::PLANE_SPRITE, 2}, + {'G', DisplayPlane::PLANE_OVERLAY, 0}, // nickname for Overlay A + {'H', DisplayPlane::PLANE_OVERLAY, 1}, // nickname for Overlay C + {'I', DisplayPlane::PLANE_CURSOR, 0}, // nickname for cursor A + {'J', DisplayPlane::PLANE_CURSOR, 1}, // nickname for cursor B + {'K', DisplayPlane::PLANE_CURSOR, 2} // nickname for cursor C +}; + + +struct ZOrderDescription { + int index; // based on overlay position + const char *zorder; +}; + +// If overlay is in the bottom of Z order, two legitimate combinations are Oa, D, E, F +// and Oc, D, E, F. However, plane A has to be part of the blending chain as it can't +// be disabled [HW bug]. The only legitimate combinations including overlay and plane A is: +// A, Oa, E, F +// A, Oc, E, F +// Cursor plane can be placed on top of any plane below and is intentionally ignored +// in the zorder table. + +// video mode panel doesn't need the primay plane A always on hack +static ZOrderDescription PIPE_A_ZORDER_DESC_VID[] = +{ + {0, "ADEF"}, // no overlay + {1, "GDEF"}, // overlay A at bottom (1 << 0) + {1, "HDEF"}, // overlay C at bottom (1 << 0) + {2, "AGEF"}, // overlay A at next to bottom (1 << 1) + {2, "AHEF"}, // overlay C at next to bottom (1 << 1) + {3, "GHEF"}, // overlay A, C at bottom + {4, "ADGF"}, // overlay A at next to top (1 << 2) + {4, "ADHF"}, // overlay C at next to top (1 << 2) + {6, "AGHF"}, // overlay A, C in between + {8, "ADEG"}, // overlay A at top (1 << 3) + {8, "ADEH"}, // overlay C at top (1 <<3) + {12, "ADGH"} // overlay A, C at top +}; + +static ZOrderDescription PIPE_A_ZORDER_DESC_CMD[] = +{ + {0, "ADEF"}, // no overlay + {1, "GEF"}, // overlay A at bottom (1 << 0) + {1, "HEF"}, // overlay C at bottom (1 << 0) + {2, "AGEF"}, // overlay A at next to bottom (1 << 1) + {2, "AHEF"}, // overlay C at next to bottom (1 << 1) + {3, "GHF"}, // overlay A, C at bottom + {4, "ADGF"}, // overlay A at next to top (1 << 2) + {4, "ADHF"}, // overlay C at next to top (1 << 2) + {6, "AGHF"}, // overlay A, C in between + {8, "ADEG"}, // overlay A at top (1 << 3) + {8, "ADEH"}, // overlay C at top (1 <<3) + {12, "ADGH"} // overlay A, C at top +}; + +// use overlay C over overlay A if possible on pipe B +static ZOrderDescription PIPE_B_ZORDER_DESC[] = +{ + {0, "BD"}, // no overlay + {1, "HBD"}, // overlay C at bottom (1 << 0) +// {1, "GBD"}, // overlay A at bottom (1 << 0), overlay A don`t switch to pipeB and only overlay C on pipeB + {2, "BHD"}, // overlay C at middle (1 << 1) +// {2, "BGD"}, // overlay A at middle (1 << 1), overlay A don`t switch to pipeB and only overaly C on pipeB + {3, "GHBD"}, // overlay A and C at bottom ( 1 << 0 + 1 << 1) + {4, "BDH"}, // overlay C at top (1 << 2) + {4, "BDG"}, // overlay A at top (1 << 2) + {6, "BGHD"}, // overlay A/C at middle 1 << 1 + 1 << 2) + {12, "BDGH"} // overlay A/C at top (1 << 2 + 1 << 3) +}; + +static ZOrderDescription *PIPE_A_ZORDER_TBL; +static int PIPE_A_ZORDER_COMBINATIONS; +static ZOrderDescription *PIPE_B_ZORDER_TBL; +static int PIPE_B_ZORDER_COMBINATIONS; +static bool OVERLAY_HW_WORKAROUND; + +AnnPlaneManager::AnnPlaneManager() + : DisplayPlaneManager() +{ +} + +AnnPlaneManager::~AnnPlaneManager() +{ +} + +bool AnnPlaneManager::initialize() +{ + mSpritePlaneCount = 3; // Sprite D, E, F + mOverlayPlaneCount = 2; // Overlay A, C + mPrimaryPlaneCount = 3; // Primary A, B, C + mCursorPlaneCount = 3; + + uint32_t videoMode = 0; + Drm *drm = Hwcomposer::getInstance().getDrm(); + drm->readIoctl(DRM_PSB_PANEL_QUERY, &videoMode, sizeof(uint32_t)); + if (videoMode == 1) { + DTRACE("video mode panel, no primay A always on hack"); + PIPE_A_ZORDER_TBL = PIPE_A_ZORDER_DESC_VID; + PIPE_A_ZORDER_COMBINATIONS = + sizeof(PIPE_A_ZORDER_DESC_VID)/sizeof(ZOrderDescription); + } else { + DTRACE("command mode panel, need primay A always on hack"); + PIPE_A_ZORDER_TBL = PIPE_A_ZORDER_DESC_CMD; + PIPE_A_ZORDER_COMBINATIONS = + sizeof(PIPE_A_ZORDER_DESC_CMD)/sizeof(ZOrderDescription); + OVERLAY_HW_WORKAROUND = true; + } + + PIPE_B_ZORDER_TBL = PIPE_B_ZORDER_DESC; + PIPE_B_ZORDER_COMBINATIONS = + sizeof(PIPE_B_ZORDER_DESC)/sizeof(ZOrderDescription); + + return DisplayPlaneManager::initialize(); +} + +void AnnPlaneManager::deinitialize() +{ + DisplayPlaneManager::deinitialize(); +} + +DisplayPlane* AnnPlaneManager::allocPlane(int index, int type) +{ + DisplayPlane *plane = NULL; + + switch (type) { + case DisplayPlane::PLANE_PRIMARY: + plane = new AnnRGBPlane(index, DisplayPlane::PLANE_PRIMARY, index/*disp*/); + break; + case DisplayPlane::PLANE_SPRITE: + plane = new AnnRGBPlane(index, DisplayPlane::PLANE_SPRITE, 0/*disp*/); + break; + case DisplayPlane::PLANE_OVERLAY: + plane = new AnnOverlayPlane(index, 0/*disp*/); + break; + case DisplayPlane::PLANE_CURSOR: + plane = new AnnCursorPlane(index, index /*disp */); + break; + default: + ETRACE("unsupported type %d", type); + break; + } + + if (plane && !plane->initialize(DisplayPlane::MIN_DATA_BUFFER_COUNT)) { + ETRACE("failed to initialize plane."); + DEINIT_AND_DELETE_OBJ(plane); + } + + return plane; +} + +bool AnnPlaneManager::isValidZOrder(int dsp, ZOrderConfig& config) +{ + int size = (int)config.size(); + bool hasCursor = false; + + for (int i = 0; i < size; i++) { + if (config[i]->planeType == DisplayPlane::PLANE_CURSOR) { + hasCursor = true; + break; + } + } + + if (size <= 0 || + (hasCursor && size > 5) || + (!hasCursor && size > 4)) { + VTRACE("invalid z order config size %d", size); + return false; + } + + if (dsp == IDisplayDevice::DEVICE_PRIMARY) { + int firstOverlay = -1; + for (int i = 0; i < size; i++) { + if (config[i]->planeType == DisplayPlane::PLANE_OVERLAY) { + firstOverlay = i; + break; + } + } + + int sprites = 0; + for (int i = 0; i < size; i++) { + if (config[i]->planeType != DisplayPlane::PLANE_OVERLAY && + config[i]->planeType != DisplayPlane::PLANE_CURSOR) { + sprites++; + } + } + + if (firstOverlay < 0 && sprites > 4) { + VTRACE("not capable to support more than 4 sprite layers"); + return false; + } + + if (OVERLAY_HW_WORKAROUND) { + if (firstOverlay == 0 && size > 2) { + VTRACE("can not support 3 sprite layers on top of overlay"); + return false; + } + } + } else if (dsp == IDisplayDevice::DEVICE_EXTERNAL) { + int sprites = 0; + for (int i = 0; i < size; i++) { + if (config[i]->planeType != DisplayPlane::PLANE_OVERLAY && + config[i]->planeType != DisplayPlane::PLANE_CURSOR) { + sprites++; + } + } + if (sprites > 2) { + ETRACE("number of sprite: %d, maximum 1 sprite and 1 primary supported on pipe 1", sprites); + return false; + } + } else { + ETRACE("invalid display device %d", dsp); + return false; + } + return true; +} + +bool AnnPlaneManager::assignPlanes(int dsp, ZOrderConfig& config) +{ + if (dsp < 0 || dsp > IDisplayDevice::DEVICE_EXTERNAL) { + ETRACE("invalid display device %d", dsp); + return false; + } + + int size = (int)config.size(); + + // calculate index based on overlay Z order position + int index = 0; + for (int i = 0; i < size; i++) { + if (config[i]->planeType == DisplayPlane::PLANE_OVERLAY) { + index += (1 << i); + } + } + + int combinations; + ZOrderDescription *table; + if (dsp == IDisplayDevice::DEVICE_PRIMARY) { + combinations = PIPE_A_ZORDER_COMBINATIONS; + table = PIPE_A_ZORDER_TBL; + } else { + combinations = PIPE_B_ZORDER_COMBINATIONS; + table = PIPE_B_ZORDER_TBL; + } + + for (int i = 0; i < combinations; i++) { + ZOrderDescription *zorderDesc = table + i; + + if (zorderDesc->index != index) + continue; + + if (assignPlanes(dsp, config, zorderDesc->zorder)) { + VTRACE("zorder assigned %s", zorderDesc->zorder); + return true; + } + } + return false; +} + +bool AnnPlaneManager::assignPlanes(int dsp, ZOrderConfig& config, const char *zorder) +{ + // zorder string does not include cursor plane, therefore cursor layer needs to be handled + // in a special way. Cursor layer must be on top of zorder and no more than one cursor layer. + + int size = (int)config.size(); + if (zorder == NULL || size == 0) { + //DTRACE("invalid zorder or ZOrder config."); + return false; + } + + int zorderLen = (int)strlen(zorder); + + // test if plane is avalable + for (int i = 0; i < size; i++) { + if (config[i]->planeType == DisplayPlane::PLANE_CURSOR) { + if (i != size - 1) { + ETRACE("invalid zorder of cursor layer"); + return false; + } + PlaneDescription& desc = PLANE_DESC['I' - 'A' + dsp]; + if (!isFreePlane(desc.type, desc.index)) { + ETRACE("cursor plane is not available"); + return false; + } + continue; + } + if (i >= zorderLen) { + DTRACE("index of ZOrderConfig is out of bound"); + return false; + } + + char id = *(zorder + i); + PlaneDescription& desc = PLANE_DESC[id - 'A']; + if (!isFreePlane(desc.type, desc.index)) { + DTRACE("plane type %d index %d is not available", desc.type, desc.index); + return false; + } + +#if 0 + // plane type check + if (config[i]->planeType == DisplayPlane::PLANE_OVERLAY && + desc.type != DisplayPlane::PLANE_OVERLAY) { + ETRACE("invalid plane type %d, expected %d", desc.type, config[i]->planeType); + return false; + } + + if (config[i]->planeType != DisplayPlane::PLANE_OVERLAY) { + if (config[i]->planeType != DisplayPlane::PLANE_PRIMARY && + config[i]->planeType != DisplayPlane::PLANE_SPRITE) { + ETRACE("invalid plane type %d,", config[i]->planeType); + return false; + } + if (desc.type != DisplayPlane::PLANE_PRIMARY && + desc.type != DisplayPlane::PLANE_SPRITE) { + ETRACE("invalid plane type %d, expected %d", desc.type, config[i]->planeType); + return false; + } + } +#endif + + if (desc.type == DisplayPlane::PLANE_OVERLAY && desc.index == 1 && + config[i]->hwcLayer->getTransform() != 0) { + DTRACE("overlay C does not support transform"); + return false; + } + } + + bool primaryPlaneActive = false; + // allocate planes + for (int i = 0; i < size; i++) { + if (config[i]->planeType == DisplayPlane::PLANE_CURSOR) { + PlaneDescription& desc = PLANE_DESC['I' - 'A' + dsp]; + ZOrderLayer *zLayer = config.itemAt(i); + zLayer->plane = getPlane(desc.type, desc.index); + if (zLayer->plane == NULL) { + ETRACE("failed to get cursor plane, should never happen!"); + } + continue; + } + + char id = *(zorder + i); + PlaneDescription& desc = PLANE_DESC[id - 'A']; + ZOrderLayer *zLayer = config.itemAt(i); + zLayer->plane = getPlane(desc.type, desc.index); + if (zLayer->plane == NULL) { + ETRACE("failed to get plane, should never happen!"); + } + // override type + zLayer->planeType = desc.type; + if (desc.type == DisplayPlane::PLANE_PRIMARY) { + primaryPlaneActive = true; + } + } + + // setup Z order + int slot = 0; + for (int i = 0; i < size; i++) { + slot = i; + + if (OVERLAY_HW_WORKAROUND) { + if (!primaryPlaneActive && + config[i]->planeType == DisplayPlane::PLANE_OVERLAY) { + slot += 1; + } + } + + config[i]->plane->setZOrderConfig(config, (void *)(unsigned long)slot); + config[i]->plane->enable(); + } + +#if 0 + DTRACE("config size %d, zorder %s", size, zorder); + for (int i = 0; i < size; i++) { + const ZOrderLayer *l = config.itemAt(i); + ITRACE("%d: plane type %d, index %d, zorder %d", + i, l->planeType, l->plane->getIndex(), l->zorder); + } +#endif + + return true; +} + +void* AnnPlaneManager::getZOrderConfig() const +{ + return NULL; +} + +int AnnPlaneManager::getFreePlanes(int dsp, int type) +{ + RETURN_NULL_IF_NOT_INIT(); + + if (type != DisplayPlane::PLANE_SPRITE) { + return DisplayPlaneManager::getFreePlanes(dsp, type); + } + + if (dsp < 0 || dsp > IDisplayDevice::DEVICE_EXTERNAL) { + ETRACE("invalid display device %d", dsp); + return 0; + } + + uint32_t freePlanes = mFreePlanes[type] | mReclaimedPlanes[type]; + int start = 0; + int stop = mSpritePlaneCount; + if (dsp == IDisplayDevice::DEVICE_EXTERNAL) { + // only Sprite D (index 0) can be assigned to pipe 1 + // Sprites E/F (index 1, 2) are fixed on pipe 0 + stop = 1; + } + int count = 0; + for (int i = start; i < stop; i++) { + if ((1 << i) & freePlanes) { + count++; + } + } + return count; +} + +} // namespace intel +} // namespace android + diff --git a/merrifield/ips/anniedale/AnnPlaneManager.h b/merrifield/ips/anniedale/AnnPlaneManager.h new file mode 100644 index 0000000..5a7971e --- /dev/null +++ b/merrifield/ips/anniedale/AnnPlaneManager.h @@ -0,0 +1,48 @@ +/* +// 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. +*/ +#ifndef ANN_PLANE_MANAGER_H +#define ANN_PLANE_MANAGER_H + +#include <DisplayPlaneManager.h> +#include <linux/psb_drm.h> + +namespace android { +namespace intel { + +class AnnPlaneManager : public DisplayPlaneManager { +public: + AnnPlaneManager(); + virtual ~AnnPlaneManager(); + +public: + virtual bool initialize(); + virtual void deinitialize(); + virtual bool isValidZOrder(int dsp, ZOrderConfig& config); + virtual bool assignPlanes(int dsp, ZOrderConfig& config); + virtual int getFreePlanes(int dsp, int type); + // TODO: remove this API + virtual void* getZOrderConfig() const; + +protected: + DisplayPlane* allocPlane(int index, int type); + bool assignPlanes(int dsp, ZOrderConfig& config, const char *zorder); +}; + +} // namespace intel +} // namespace android + + +#endif /* ANN_PLANE_MANAGER_H */ diff --git a/merrifield/ips/anniedale/AnnRGBPlane.cpp b/merrifield/ips/anniedale/AnnRGBPlane.cpp new file mode 100644 index 0000000..dfc4b8c --- /dev/null +++ b/merrifield/ips/anniedale/AnnRGBPlane.cpp @@ -0,0 +1,335 @@ +/* +// 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 <Hwcomposer.h> +#include <BufferManager.h> +#include <anniedale/AnnRGBPlane.h> +#include <tangier/TngGrallocBuffer.h> +#include <common/PixelFormat.h> + +namespace android { +namespace intel { + +AnnRGBPlane::AnnRGBPlane(int index, int type, int disp) + : DisplayPlane(index, type, disp) +{ + CTRACE(); + memset(&mContext, 0, sizeof(mContext)); +} + +AnnRGBPlane::~AnnRGBPlane() +{ + CTRACE(); +} + +bool AnnRGBPlane::enable() +{ + return enablePlane(true); +} + +bool AnnRGBPlane::disable() +{ + return enablePlane(false); +} + +void* AnnRGBPlane::getContext() const +{ + CTRACE(); + return (void *)&mContext; +} + +void AnnRGBPlane::setZOrderConfig(ZOrderConfig& config, void *nativeConfig) +{ + CTRACE(); +} + +bool AnnRGBPlane::setDataBuffer(buffer_handle_t handle) +{ + if (!handle) { + setFramebufferTarget(handle); + return true; + } + + TngGrallocBuffer tmpBuf(handle); + uint32_t usage; + bool ret; + + ATRACE("handle = %#x", handle); + + usage = tmpBuf.getUsage(); + if (GRALLOC_USAGE_HW_FB & usage) { + setFramebufferTarget(handle); + return true; + } + + // use primary as a sprite + ret = DisplayPlane::setDataBuffer(handle); + if (ret == false) { + ETRACE("failed to set data buffer"); + return ret; + } + + return true; +} + +bool AnnRGBPlane::setDataBuffer(BufferMapper& mapper) +{ + int bpp; + int srcX, srcY, srcW, srcH; + int dstX, dstY, dstW, dstH; + uint32_t spriteFormat; + uint32_t stride; + uint32_t linoff; + uint32_t planeAlpha; + drmModeModeInfoPtr mode = &mModeInfo; + + CTRACE(); + + // setup plane position + dstX = mPosition.x; + dstY = mPosition.y; + dstW = mPosition.w; + dstH = mPosition.h; + + checkPosition(dstX, dstY, dstW, dstH); + + // setup plane format + if (!PixelFormat::convertFormat(mapper.getFormat(), spriteFormat, bpp)) { + ETRACE("unsupported format %#x", mapper.getFormat()); + return false; + } + + // setup stride and source buffer crop + srcX = mapper.getCrop().x; + srcY = mapper.getCrop().y; + srcW = mapper.getWidth(); + srcH = mapper.getHeight(); + stride = mapper.getStride().rgb.stride; + + if (mPanelOrientation == PANEL_ORIENTATION_180) + linoff = srcY * stride + srcX * bpp + (mapper.getCrop().h - 1) * stride + (mapper.getCrop().w - 1) * bpp; + else + linoff = srcY * stride + srcX * bpp; + + // unlikely happen, but still we need make sure linoff is valid + if (linoff > (stride * mapper.getHeight())) { + ETRACE("invalid source crop"); + return false; + } + + // update context + if (mType == PLANE_SPRITE) + mContext.type = DC_SPRITE_PLANE; + else + mContext.type = DC_PRIMARY_PLANE; + + // setup plane alpha + if (0 < mPlaneAlpha && mPlaneAlpha < 0xff) { + planeAlpha = mPlaneAlpha | 0x80000000; + } else { + // disable plane alpha to offload HW + planeAlpha = 0xff; + } + + mContext.ctx.sp_ctx.index = mIndex; + mContext.ctx.sp_ctx.pipe = mDevice; + mContext.ctx.sp_ctx.cntr = spriteFormat | 0x80000000; + mContext.ctx.sp_ctx.linoff = linoff; + mContext.ctx.sp_ctx.stride = stride; + + // turn off premultipled alpha blending for HWC_BLENDING_COVERAGE + if (mBlending == HWC_BLENDING_COVERAGE) { + mContext.ctx.sp_ctx.cntr |= (0x1 << 23); + } + + if (mPanelOrientation == PANEL_ORIENTATION_180) + mContext.ctx.sp_ctx.cntr |= (0x1 << 15); + + if (mapper.isCompression()) { + mContext.ctx.sp_ctx.stride = align_to(srcW, 32) * 4; + mContext.ctx.sp_ctx.linoff = (align_to(srcW, 32) * srcH / 64) - 1; + mContext.ctx.sp_ctx.tileoff = (srcY & 0xfff) << 16 | (srcX & 0xfff); + mContext.ctx.sp_ctx.cntr |= (0x1 << 11); + } + + mContext.ctx.sp_ctx.surf = mapper.getGttOffsetInPage(0) << 12; + mContext.gtt_key = (uint64_t)mapper.getCpuAddress(0); + + if (mPanelOrientation == PANEL_ORIENTATION_180) { + if (mode->vdisplay && mode->hdisplay) + mContext.ctx.sp_ctx.pos = ((mode->vdisplay - dstY - dstH) & 0xfff) << 16 | ((mode->hdisplay - dstX - dstW) & 0xfff); + else + mContext.ctx.sp_ctx.pos = (dstY & 0xfff) << 16 | (dstX & 0xfff); + } else { + mContext.ctx.sp_ctx.pos = (dstY & 0xfff) << 16 | (dstX & 0xfff); + } + + mContext.ctx.sp_ctx.size = + ((dstH - 1) & 0xfff) << 16 | ((dstW - 1) & 0xfff); + mContext.ctx.sp_ctx.contalpa = planeAlpha; + mContext.ctx.sp_ctx.update_mask = SPRITE_UPDATE_ALL; + + VTRACE("type = %d, index = %d, cntr = %#x, linoff = %#x, stride = %#x," + "surf = %#x, pos = %#x, size = %#x, contalpa = %#x", mType, mIndex, + mContext.ctx.sp_ctx.cntr, + mContext.ctx.sp_ctx.linoff, + mContext.ctx.sp_ctx.stride, + mContext.ctx.sp_ctx.surf, + mContext.ctx.sp_ctx.pos, + mContext.ctx.sp_ctx.size, + mContext.ctx.sp_ctx.contalpa); + return true; +} + +bool AnnRGBPlane::enablePlane(bool enabled) +{ + RETURN_FALSE_IF_NOT_INIT(); + + struct drm_psb_register_rw_arg arg; + memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); + if (enabled) { + arg.plane_enable_mask = 1; + } else { + arg.plane_disable_mask = 1; + } + + if (mType == PLANE_SPRITE) + arg.plane.type = DC_SPRITE_PLANE; + else + arg.plane.type = DC_PRIMARY_PLANE; + + arg.plane.index = mIndex; + arg.plane.ctx = 0; + + // issue ioctl + Drm *drm = Hwcomposer::getInstance().getDrm(); + bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); + if (ret == false) { + WTRACE("plane enabling (%d) failed with error code %d", enabled, ret); + return false; + } + + return true; +} + +bool AnnRGBPlane::isDisabled() +{ + RETURN_FALSE_IF_NOT_INIT(); + + struct drm_psb_register_rw_arg arg; + memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); + + if (mType == PLANE_SPRITE) + arg.plane.type = DC_SPRITE_PLANE; + else + arg.plane.type = DC_PRIMARY_PLANE; + + arg.get_plane_state_mask = 1; + arg.plane.index = mIndex; + arg.plane.ctx = 0; + + // issue ioctl + Drm *drm = Hwcomposer::getInstance().getDrm(); + bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); + if (ret == false) { + WTRACE("plane state query failed with error code %d", ret); + return false; + } + + return arg.plane.ctx == PSB_DC_PLANE_DISABLED; +} + +void AnnRGBPlane::postFlip() +{ + // prevent mUpdateMasks from being reset + // skipping flip may cause flicking +} + +void AnnRGBPlane::setFramebufferTarget(buffer_handle_t handle) +{ + uint32_t stride; + uint32_t planeAlpha; + + CTRACE(); + + // do not need to update the buffer handle + if (mCurrentDataBuffer != handle) + mUpdateMasks |= PLANE_BUFFER_CHANGED; + else + mUpdateMasks &= ~PLANE_BUFFER_CHANGED; + + // if no update then do Not need set data buffer + if (!mUpdateMasks) + return; + + // don't need to map data buffer for primary plane + if (mType == PLANE_SPRITE) + mContext.type = DC_SPRITE_PLANE; + else + mContext.type = DC_PRIMARY_PLANE; + + stride = align_to((4 * align_to(mPosition.w, 32)), 64); + + if (0 < mPlaneAlpha && mPlaneAlpha < 0xff) { + planeAlpha = mPlaneAlpha | 0x80000000; + } else { + // disable plane alpha to offload HW + planeAlpha = 0xff; + } + + // FIXME: use sprite context for sprite plane + mContext.ctx.prim_ctx.update_mask = SPRITE_UPDATE_ALL; + mContext.ctx.prim_ctx.index = mIndex; + mContext.ctx.prim_ctx.pipe = mDevice; + + if (mPanelOrientation == PANEL_ORIENTATION_180) + mContext.ctx.prim_ctx.linoff = (mPosition.h - 1) * stride + (mPosition.w - 1) * 4; + else + mContext.ctx.prim_ctx.linoff = 0; + + mContext.ctx.prim_ctx.stride = stride; + mContext.ctx.prim_ctx.tileoff = 0; + mContext.ctx.prim_ctx.pos = 0; + mContext.ctx.prim_ctx.size = + ((mPosition.h - 1) & 0xfff) << 16 | ((mPosition.w - 1) & 0xfff); + mContext.ctx.prim_ctx.surf = 0; + mContext.ctx.prim_ctx.contalpa = planeAlpha; + mContext.ctx.prim_ctx.cntr = PixelFormat::PLANE_PIXEL_FORMAT_BGRA8888; + mContext.ctx.prim_ctx.cntr |= 0x80000000; + + // turn off premultipled alpha blending for HWC_BLENDING_COVERAGE + if (mBlending == HWC_BLENDING_COVERAGE) { + mContext.ctx.prim_ctx.cntr |= (0x1 << 23); + } + + if (mPanelOrientation == PANEL_ORIENTATION_180) + mContext.ctx.prim_ctx.cntr |= (0x1 << 15); + + VTRACE("type = %d, index = %d, cntr = %#x, linoff = %#x, stride = %#x," + "surf = %#x, pos = %#x, size = %#x, contalpa = %#x", mType, mIndex, + mContext.ctx.prim_ctx.cntr, + mContext.ctx.prim_ctx.linoff, + mContext.ctx.prim_ctx.stride, + mContext.ctx.prim_ctx.surf, + mContext.ctx.prim_ctx.pos, + mContext.ctx.prim_ctx.size, + mContext.ctx.sp_ctx.contalpa); + + mCurrentDataBuffer = handle; +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/anniedale/AnnRGBPlane.h b/merrifield/ips/anniedale/AnnRGBPlane.h new file mode 100644 index 0000000..d1a9e60 --- /dev/null +++ b/merrifield/ips/anniedale/AnnRGBPlane.h @@ -0,0 +1,57 @@ +/* +// 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. +*/ +#ifndef ANN_RGB_PLANE_H +#define ANN_RGB_PLANE_H + +#include <utils/KeyedVector.h> +#include <hal_public.h> +#include <Hwcomposer.h> +#include <BufferCache.h> +#include <DisplayPlane.h> + +#include <linux/psb_drm.h> + +namespace android { +namespace intel { + +class AnnRGBPlane : public DisplayPlane { +public: + AnnRGBPlane(int index, int type, int disp); + virtual ~AnnRGBPlane(); +public: + // hardware operations + bool enable(); + bool disable(); + bool isDisabled(); + void postFlip(); + + void* getContext() const; + void setZOrderConfig(ZOrderConfig& config, void *nativeConfig); + + bool setDataBuffer(buffer_handle_t handle); +protected: + bool setDataBuffer(BufferMapper& mapper); + bool enablePlane(bool enabled); +private: + void setFramebufferTarget(buffer_handle_t handle); +protected: + struct intel_dc_plane_ctx mContext; +}; + +} // namespace intel +} // namespace android + +#endif /* ANN_RGB_PLANE_H */ diff --git a/merrifield/ips/anniedale/PlaneCapabilities.cpp b/merrifield/ips/anniedale/PlaneCapabilities.cpp new file mode 100644 index 0000000..853511b --- /dev/null +++ b/merrifield/ips/anniedale/PlaneCapabilities.cpp @@ -0,0 +1,280 @@ +/* +// 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 + diff --git a/merrifield/ips/common/BlankControl.cpp b/merrifield/ips/common/BlankControl.cpp new file mode 100644 index 0000000..3ac0736 --- /dev/null +++ b/merrifield/ips/common/BlankControl.cpp @@ -0,0 +1,43 @@ +/* +// 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 <Drm.h> +#include <common/BlankControl.h> +#include <Hwcomposer.h> + +namespace android { +namespace intel { + +BlankControl::BlankControl() + : IBlankControl() +{ +} + +BlankControl::~BlankControl() +{ +} + +bool BlankControl::blank(int disp, bool blank) +{ + // current do nothing but return true + // use PM to trigger screen blank/unblank + VTRACE("blank is not supported yet, disp %d, blank %d", disp, blank); + return true; +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/common/BlankControl.h b/merrifield/ips/common/BlankControl.h new file mode 100644 index 0000000..1c0de05 --- /dev/null +++ b/merrifield/ips/common/BlankControl.h @@ -0,0 +1,36 @@ +/* +// 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. +*/ +#ifndef BLANK_CONTROL_H +#define BLANK_CONTROL_H + +#include <IBlankControl.h> + +namespace android { +namespace intel { + +class BlankControl : public IBlankControl { +public: + BlankControl(); + virtual ~BlankControl(); + +public: + bool blank(int disp, bool blank); +}; + +} // namespace intel +} // namespace android + +#endif /* BLANK_CONTROL_H */ diff --git a/merrifield/ips/common/DrmConfig.cpp b/merrifield/ips/common/DrmConfig.cpp new file mode 100644 index 0000000..59b1c72 --- /dev/null +++ b/merrifield/ips/common/DrmConfig.cpp @@ -0,0 +1,90 @@ +/* +// 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 <IDisplayDevice.h> +#include <Drm.h> +#include <DrmConfig.h> + + +namespace android { +namespace intel { + +const char* DrmConfig::getDrmPath() +{ + return "/dev/card0"; +} + +uint32_t DrmConfig::getDrmConnector(int device) +{ + if (device == IDisplayDevice::DEVICE_PRIMARY) + return DRM_MODE_CONNECTOR_MIPI; + else if (device == IDisplayDevice::DEVICE_EXTERNAL) + return DRM_MODE_CONNECTOR_DVID; + return DRM_MODE_CONNECTOR_Unknown; +} + +uint32_t DrmConfig::getDrmEncoder(int device) +{ + if (device == IDisplayDevice::DEVICE_PRIMARY) + return DRM_MODE_ENCODER_MIPI; + else if (device == IDisplayDevice::DEVICE_EXTERNAL) + return DRM_MODE_ENCODER_TMDS; + return DRM_MODE_ENCODER_NONE; +} + +uint32_t DrmConfig::getFrameBufferFormat() +{ + return HAL_PIXEL_FORMAT_RGBX_8888; +} + +uint32_t DrmConfig::getFrameBufferDepth() +{ + return 24; +} + +uint32_t DrmConfig::getFrameBufferBpp() +{ + return 32; +} + +const char* DrmConfig::getUeventEnvelope() +{ + return "change@/devices/pci0000:00/0000:00:02.0/drm/card0"; +} + +const char* DrmConfig::getHotplugString() +{ + return "HOTPLUG=1"; +} + +const char* DrmConfig::getRepeatedFrameString() +{ + return "REPEATED_FRAME"; +} + +uint32_t DrmConfig::convertHalFormatToDrmFormat(uint32_t halFormat) +{ + switch (halFormat) { + case HAL_PIXEL_FORMAT_RGBX_8888: + return DRM_FORMAT_XRGB8888; + default: + ETRACE("format %#x isn't supported by drm", halFormat); + return 0; + } +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/common/DrmControl.cpp b/merrifield/ips/common/DrmControl.cpp new file mode 100644 index 0000000..9c34658 --- /dev/null +++ b/merrifield/ips/common/DrmControl.cpp @@ -0,0 +1,58 @@ +/* +// 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 <linux/psb_drm.h> +#include <Hwcomposer.h> +#include <common/DrmControl.h> + +namespace android { +namespace intel { + +DrmControl::DrmControl() + : mVideoExtCommand(0) +{ +} + +DrmControl::~DrmControl() +{ +} + +int DrmControl::getVideoExtCommand() +{ + if (mVideoExtCommand) { + return mVideoExtCommand; + } + + int fd = Hwcomposer::getInstance().getDrm()->getDrmFd(); + + union drm_psb_extension_arg video_getparam_arg; + strncpy(video_getparam_arg.extension, + "lnc_video_getparam", sizeof(video_getparam_arg.extension)); + int ret = drmCommandWriteRead(fd, DRM_PSB_EXTENSION, + &video_getparam_arg, sizeof(video_getparam_arg)); + if (ret != 0) { + VTRACE("failed to get video extension command"); + return 0; + } + + mVideoExtCommand = video_getparam_arg.rep.driver_ioctl_offset; + + return mVideoExtCommand; +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/common/DrmControl.h b/merrifield/ips/common/DrmControl.h new file mode 100644 index 0000000..fbd0284 --- /dev/null +++ b/merrifield/ips/common/DrmControl.h @@ -0,0 +1,38 @@ +/* +// 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. +*/ +#ifndef DRM_CONTROL_H +#define DRM_CONTROL_H + + +namespace android { +namespace intel { + +class DrmControl { +public: + DrmControl(); + virtual ~DrmControl(); + +public: + int getVideoExtCommand(); + +private: + int mVideoExtCommand; +}; + +} // namespace intel +} // namespace android + +#endif /* DRM_CONTROL_H */ diff --git a/merrifield/ips/common/GrallocBufferBase.cpp b/merrifield/ips/common/GrallocBufferBase.cpp new file mode 100644 index 0000000..e50b777 --- /dev/null +++ b/merrifield/ips/common/GrallocBufferBase.cpp @@ -0,0 +1,91 @@ +/* +// 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 <common/GrallocBufferBase.h> +#include <DisplayQuery.h> + + +namespace android { +namespace intel { + +GrallocBufferBase::GrallocBufferBase(buffer_handle_t handle) + : GraphicBuffer(handle) +{ + ATRACE("handle = %#x", handle); + initBuffer(handle); +} + +void GrallocBufferBase::resetBuffer(buffer_handle_t handle) +{ + GraphicBuffer::resetBuffer(handle); + initBuffer(handle); +} + +void GrallocBufferBase::initBuffer(buffer_handle_t handle) +{ + // nothing to initialize +} + +void GrallocBufferBase::initStride() +{ + int yStride, uvStride; + + // setup stride + switch (mFormat) { + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_I420: + uint32_t yStride_align; + yStride_align = DisplayQuery::getOverlayLumaStrideAlignment(mFormat); + if (yStride_align > 0) + { + yStride = align_to(align_to(mWidth, 32), yStride_align); + } + else + { + yStride = align_to(align_to(mWidth, 32), 64); + } + uvStride = align_to(yStride >> 1, 64); + mStride.yuv.yStride = yStride; + mStride.yuv.uvStride = uvStride; + break; + case HAL_PIXEL_FORMAT_NV12: + yStride = align_to(align_to(mWidth, 32), 64); + uvStride = yStride; + mStride.yuv.yStride = yStride; + mStride.yuv.uvStride = uvStride; + break; + case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: + case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: + yStride = align_to(align_to(mWidth, 32), 64); + uvStride = yStride; + mStride.yuv.yStride = yStride; + mStride.yuv.uvStride = uvStride; + break; + case HAL_PIXEL_FORMAT_YUY2: + case HAL_PIXEL_FORMAT_UYVY: + yStride = align_to((align_to(mWidth, 32) << 1), 64); + uvStride = 0; + mStride.yuv.yStride = yStride; + mStride.yuv.uvStride = uvStride; + break; + default: + mStride.rgb.stride = align_to(((mBpp >> 3) * align_to(mWidth, 32)), 64); + break; + } +} + +} +} diff --git a/merrifield/ips/common/GrallocBufferBase.h b/merrifield/ips/common/GrallocBufferBase.h new file mode 100644 index 0000000..5ae8c95 --- /dev/null +++ b/merrifield/ips/common/GrallocBufferBase.h @@ -0,0 +1,45 @@ +/* +// 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. +*/ +#ifndef GRALLOC_BUFFER_BASE_H +#define GRALLOC_BUFFER_BASE_H + +#include <GraphicBuffer.h> +#include <hal_public.h> +// FIXME: remove it, why define NV12_VED based on OMX's value? +#include <OMX_IVCommon.h> +#include <OMX_IntelVideoExt.h> + +namespace android { +namespace intel { + +class GrallocBufferBase : public GraphicBuffer { +public: + GrallocBufferBase(buffer_handle_t handle); + virtual ~GrallocBufferBase() {} + virtual void resetBuffer(buffer_handle_t handle); + +protected: + // helper function to be invoked by the derived class + void initStride(); + +private: + void initBuffer(buffer_handle_t handle); +}; + +} // namespace intel +} // namespace android + +#endif /* GRALLOC_BUFFER_BASE_H */ diff --git a/merrifield/ips/common/GrallocBufferMapperBase.cpp b/merrifield/ips/common/GrallocBufferMapperBase.cpp new file mode 100644 index 0000000..ac236e3 --- /dev/null +++ b/merrifield/ips/common/GrallocBufferMapperBase.cpp @@ -0,0 +1,72 @@ +/* +// 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 <Drm.h> +#include <Hwcomposer.h> +#include <common/GrallocBufferMapperBase.h> + +namespace android { +namespace intel { + +GrallocBufferMapperBase::GrallocBufferMapperBase(DataBuffer& buffer) + : BufferMapper(buffer) +{ + CTRACE(); + + for (int i = 0; i < SUB_BUFFER_MAX; i++) { + mGttOffsetInPage[i] = 0; + mCpuAddress[i] = 0; + mSize[i] = 0; + mKHandle[i] = 0; + } +} + +GrallocBufferMapperBase::~GrallocBufferMapperBase() +{ + CTRACE(); +} + +uint32_t GrallocBufferMapperBase::getGttOffsetInPage(int subIndex) const +{ + if (subIndex >= 0 && subIndex < SUB_BUFFER_MAX) + return mGttOffsetInPage[subIndex]; + return 0; +} + +void* GrallocBufferMapperBase::getCpuAddress(int subIndex) const +{ + if (subIndex >=0 && subIndex < SUB_BUFFER_MAX) + return mCpuAddress[subIndex]; + return 0; +} + +uint32_t GrallocBufferMapperBase::getSize(int subIndex) const +{ + if (subIndex >= 0 && subIndex < SUB_BUFFER_MAX) + return mSize[subIndex]; + return 0; +} + +buffer_handle_t GrallocBufferMapperBase::getKHandle(int subIndex) +{ + if (subIndex >= 0 && subIndex < SUB_BUFFER_MAX) + return mKHandle[subIndex]; + return 0; +} + + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/common/GrallocBufferMapperBase.h b/merrifield/ips/common/GrallocBufferMapperBase.h new file mode 100644 index 0000000..fed0d8e --- /dev/null +++ b/merrifield/ips/common/GrallocBufferMapperBase.h @@ -0,0 +1,52 @@ +/* +// 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. +*/ +#ifndef GRALLOC_BUFFER_MAPPER_BASE_H +#define GRALLOC_BUFFER_MAPPER_BASE_H + +#include <BufferMapper.h> +#include <common/GrallocSubBuffer.h> +#include <common/GrallocBufferBase.h> + +namespace android { +namespace intel { + +class GrallocBufferMapperBase : public BufferMapper { +public: + GrallocBufferMapperBase(DataBuffer& buffer); + virtual ~GrallocBufferMapperBase(); +public: + virtual bool map() = 0; + virtual bool unmap() = 0; + + uint32_t getGttOffsetInPage(int subIndex) const; + void* getCpuAddress(int subIndex) const; + uint32_t getSize(int subIndex) const; + virtual buffer_handle_t getKHandle(int subIndex); + virtual buffer_handle_t getFbHandle(int subIndex) = 0; + virtual void putFbHandle() = 0; + +protected: + // mapped info + uint32_t mGttOffsetInPage[SUB_BUFFER_MAX]; + void* mCpuAddress[SUB_BUFFER_MAX]; + uint32_t mSize[SUB_BUFFER_MAX]; + buffer_handle_t mKHandle[SUB_BUFFER_MAX]; +}; + +} // namespace intel +} // namespace android + +#endif /* TNG_GRALLOC_BUFFER_MAPPER_H */ diff --git a/merrifield/ips/common/GrallocSubBuffer.h b/merrifield/ips/common/GrallocSubBuffer.h new file mode 100644 index 0000000..15170f2 --- /dev/null +++ b/merrifield/ips/common/GrallocSubBuffer.h @@ -0,0 +1,35 @@ +/* +// 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. +*/ +#ifndef GRALLOC_SUB_BUFFER_H +#define GRALLOC_SUB_BUFFER_H + + +namespace android { +namespace intel { + +enum { + SUB_BUFFER0 = 0, + SUB_BUFFER1, + SUB_BUFFER2, + SUB_BUFFER_MAX, +}; + +} // namespace intel +} // namespace android + + +#endif /* GRALLOC_SUB_BUFFER_H */ + diff --git a/merrifield/ips/common/HdcpControl.cpp b/merrifield/ips/common/HdcpControl.cpp new file mode 100644 index 0000000..620d28f --- /dev/null +++ b/merrifield/ips/common/HdcpControl.cpp @@ -0,0 +1,380 @@ +/* +// 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 <DrmConfig.h> +#include <Hwcomposer.h> +#include <DisplayQuery.h> +#include <common/DrmControl.h> +#include <common/HdcpControl.h> +#include <cutils/properties.h> + + +namespace android { +namespace intel { + +HdcpControl::HdcpControl() + : mCallback(NULL), + mUserData(NULL), + mCallbackState(CALLBACK_PENDING), + mMutex(), + mStoppedCondition(), + mCompletedCondition(), + mWaitForCompletion(false), + mStopped(true), + mAuthenticated(false), + mActionDelay(0), + mAuthRetryCount(0) +{ +} + +HdcpControl::~HdcpControl() +{ +} + +bool HdcpControl::startHdcp() +{ + // this is a blocking and synchronous call + Mutex::Autolock lock(mMutex); + + char prop[PROPERTY_VALUE_MAX]; + if (property_get("debug.hwc.hdcp.enable", prop, "1") > 0) { + if (atoi(prop) == 0) { + WTRACE("HDCP is disabled"); + return false; + } + } + + if (!mStopped) { + WTRACE("HDCP has been started"); + return true; + } + + mStopped = false; + mAuthenticated = false; + mWaitForCompletion = false; + + mThread = new HdcpControlThread(this); + if (!mThread.get()) { + ETRACE("failed to create hdcp control thread"); + return false; + } + + if (!runHdcp()) { + ETRACE("failed to run HDCP"); + mStopped = true; + mThread = NULL; + return false; + } + + mAuthRetryCount = 0; + mWaitForCompletion = !mAuthenticated; + if (mAuthenticated) { + mActionDelay = HDCP_VERIFICATION_DELAY_MS; + } else { + mActionDelay = HDCP_AUTHENTICATION_SHORT_DELAY_MS; + } + + mThread->run("HdcpControl", PRIORITY_NORMAL); + + if (!mWaitForCompletion) { + // HDCP is authenticated. + return true; + } + status_t err = mCompletedCondition.waitRelative(mMutex, milliseconds(HDCP_AUTHENTICATION_TIMEOUT_MS)); + if (err == -ETIMEDOUT) { + WTRACE("timeout waiting for completion"); + } + mWaitForCompletion = false; + return mAuthenticated; +} + +bool HdcpControl::startHdcpAsync(HdcpStatusCallback cb, void *userData) +{ + char prop[PROPERTY_VALUE_MAX]; + if (property_get("debug.hwc.hdcp.enable", prop, "1") > 0) { + if (atoi(prop) == 0) { + WTRACE("HDCP is disabled"); + return false; + } + } + + if (cb == NULL || userData == NULL) { + ETRACE("invalid callback or user data"); + return false; + } + + Mutex::Autolock lock(mMutex); + + if (!mStopped) { + WTRACE("HDCP has been started"); + return true; + } + + mThread = new HdcpControlThread(this); + if (!mThread.get()) { + ETRACE("failed to create hdcp control thread"); + return false; + } + + mAuthRetryCount = 0; + mCallback = cb; + mUserData = userData; + mCallbackState = CALLBACK_PENDING; + mWaitForCompletion = false; + mAuthenticated = false; + mStopped = false; + mActionDelay = HDCP_ASYNC_START_DELAY_MS; + mThread->run("HdcpControl", PRIORITY_NORMAL); + + return true; +} + +bool HdcpControl::stopHdcp() +{ + do { + Mutex::Autolock lock(mMutex); + if (mStopped) { + return true; + } + + mStopped = true; + mStoppedCondition.signal(); + + mAuthenticated = false; + mWaitForCompletion = false; + mCallback = NULL; + mUserData = NULL; + disableAuthentication(); + } while (0); + + if (mThread.get()) { + mThread->requestExitAndWait(); + mThread = NULL; + } + + return true; +} + +bool HdcpControl::enableAuthentication() +{ + int fd = Hwcomposer::getInstance().getDrm()->getDrmFd(); + int ret = drmCommandNone(fd, DRM_PSB_ENABLE_HDCP); + if (ret != 0) { + ETRACE("failed to enable HDCP authentication"); + return false; + } + return true; +} + +bool HdcpControl::disableAuthentication() +{ + int fd = Hwcomposer::getInstance().getDrm()->getDrmFd(); + int ret = drmCommandNone(fd, DRM_PSB_DISABLE_HDCP); + if (ret != 0) { + ETRACE("failed to stop disable authentication"); + return false; + } + return true; +} + +bool HdcpControl::enableOverlay() +{ + return true; +} + +bool HdcpControl::disableOverlay() +{ + return true; +} + +bool HdcpControl::enableDisplayIED() +{ + int fd = Hwcomposer::getInstance().getDrm()->getDrmFd(); + int ret = drmCommandNone(fd, DRM_PSB_HDCP_DISPLAY_IED_ON); + if (ret != 0) { + ETRACE("failed to enable overlay IED"); + return false; + } + return true; +} + +bool HdcpControl::disableDisplayIED() +{ + int fd = Hwcomposer::getInstance().getDrm()->getDrmFd(); + int ret = drmCommandNone(fd, DRM_PSB_HDCP_DISPLAY_IED_OFF); + if (ret != 0) { + ETRACE("failed to disable overlay IED"); + return false; + } + return true; +} + +bool HdcpControl::isHdcpSupported() +{ + int fd = Hwcomposer::getInstance().getDrm()->getDrmFd(); + unsigned int caps = 0; + int ret = drmCommandRead(fd, DRM_PSB_QUERY_HDCP, &caps, sizeof(caps)); + if (ret != 0) { + ETRACE("failed to query HDCP capability"); + return false; + } + if (caps == 0) { + WTRACE("HDCP is not supported"); + return false; + } else { + ITRACE("HDCP is supported"); + return true; + } +} + +bool HdcpControl::checkAuthenticated() +{ + int fd = Hwcomposer::getInstance().getDrm()->getDrmFd(); + unsigned int match = 0; + int ret = drmCommandRead(fd, DRM_PSB_GET_HDCP_LINK_STATUS, &match, sizeof(match)); + if (ret != 0) { + ETRACE("failed to get hdcp link status"); + return false; + } + if (match) { + VTRACE("HDCP is authenticated"); + mAuthenticated = true; + } else { + ETRACE("HDCP is not authenticated"); + mAuthenticated = false; + } + return mAuthenticated; +} + +bool HdcpControl::runHdcp() +{ + // Default return value is true so HDCP can be re-authenticated in the working thread + bool ret = true; + + preRunHdcp(); + + for (int i = 0; i < HDCP_INLOOP_RETRY_NUMBER; i++) { + VTRACE("enable and verify HDCP, iteration# %d", i); + if (mStopped) { + WTRACE("HDCP authentication has been stopped"); + ret = false; + break; + } + + if (!enableAuthentication()) { + ETRACE("HDCP authentication failed. Retry"); + mAuthenticated = false; + ret = true; + } else { + ITRACE("HDCP is authenticated"); + mAuthenticated = true; + ret = true; + break; + } + + if (mStopped) { + WTRACE("HDCP authentication has been stopped"); + ret = false; + break; + } + + if (i < HDCP_INLOOP_RETRY_NUMBER - 1) { + // Adding delay to make sure panel receives video signal so it can start HDCP authentication. + // (HDCP spec 1.3, section 2.3) + usleep(HDCP_INLOOP_RETRY_DELAY_US); + } + } + + postRunHdcp(); + + return ret; +} + +bool HdcpControl::preRunHdcp() +{ + // TODO: for CTP platform, IED needs to be disabled during HDCP authentication. + return true; +} + +bool HdcpControl::postRunHdcp() +{ + // TODO: for CTP platform, IED needs to be disabled during HDCP authentication. + return true; +} + + +void HdcpControl::signalCompletion() +{ + if (mWaitForCompletion) { + ITRACE("signal HDCP authentication completed, status = %d", mAuthenticated); + mCompletedCondition.signal(); + mWaitForCompletion = false; + } +} + +bool HdcpControl::threadLoop() +{ + Mutex::Autolock lock(mMutex); + status_t err = mStoppedCondition.waitRelative(mMutex, milliseconds(mActionDelay)); + if (err != -ETIMEDOUT) { + ITRACE("Hdcp is stopped."); + signalCompletion(); + return false; + } + + // default is to keep thread active + bool ret = true; + if (!mAuthenticated) { + ret = runHdcp(); + mAuthRetryCount++; + } else { + mAuthRetryCount = 0; + checkAuthenticated(); + } + + // set next action delay + if (mAuthenticated) { + mActionDelay = HDCP_VERIFICATION_DELAY_MS; + } else { + // If HDCP can not authenticate after "HDCP_RETRY_LIMIT" attempts + // reduce HDCP retry frequency to 2 sec + if (mAuthRetryCount >= HDCP_RETRY_LIMIT) { + mActionDelay = HDCP_AUTHENTICATION_LONG_DELAY_MS; + } else { + mActionDelay = HDCP_AUTHENTICATION_SHORT_DELAY_MS; + } + } + + // TODO: move out of lock? + if (!ret || mAuthenticated) { + signalCompletion(); + } + + if (mCallback) { + if ((mAuthenticated && mCallbackState == CALLBACK_AUTHENTICATED) || + (!mAuthenticated && mCallbackState == CALLBACK_NOT_AUTHENTICATED)) { + // ignore callback as state is not changed + } else { + mCallbackState = + mAuthenticated ? CALLBACK_AUTHENTICATED : CALLBACK_NOT_AUTHENTICATED; + (*mCallback)(mAuthenticated, mUserData); + } + } + return ret; +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/common/HdcpControl.h b/merrifield/ips/common/HdcpControl.h new file mode 100644 index 0000000..5dc33c9 --- /dev/null +++ b/merrifield/ips/common/HdcpControl.h @@ -0,0 +1,87 @@ +/* +// 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. +*/ +#ifndef HDCP_CONTROL_H +#define HDCP_CONTROL_H + +#include <IHdcpControl.h> +#include <SimpleThread.h> + +namespace android { +namespace intel { + +class HdcpControl : public IHdcpControl { +public: + HdcpControl(); + virtual ~HdcpControl(); + +public: + virtual bool startHdcp(); + virtual bool startHdcpAsync(HdcpStatusCallback cb, void *userData); + virtual bool stopHdcp(); + +protected: + bool enableAuthentication(); + bool disableAuthentication(); + bool enableOverlay(); + bool disableOverlay(); + bool enableDisplayIED(); + bool disableDisplayIED(); + bool isHdcpSupported(); + bool checkAuthenticated(); + virtual bool preRunHdcp(); + virtual bool postRunHdcp(); + bool runHdcp(); + inline void signalCompletion(); + +private: + enum { + HDCP_INLOOP_RETRY_NUMBER = 1, + HDCP_INLOOP_RETRY_DELAY_US = 50000, + HDCP_VERIFICATION_DELAY_MS = 2000, + HDCP_ASYNC_START_DELAY_MS = 100, + HDCP_AUTHENTICATION_SHORT_DELAY_MS = 200, + HDCP_AUTHENTICATION_LONG_DELAY_MS = 2000, + HDCP_AUTHENTICATION_TIMEOUT_MS = 5000, + HDCP_RETRY_LIMIT = 10, + }; + + enum { + CALLBACK_PENDING, + CALLBACK_AUTHENTICATED, + CALLBACK_NOT_AUTHENTICATED, + }; + +protected: + HdcpStatusCallback mCallback; + void *mUserData; + int mCallbackState; + Mutex mMutex; + Condition mStoppedCondition; + Condition mCompletedCondition; + bool mWaitForCompletion; + bool mStopped; + bool mAuthenticated; + int mActionDelay; // in milliseconds + uint32_t mAuthRetryCount; + +private: + DECLARE_THREAD(HdcpControlThread, HdcpControl); +}; + +} // namespace intel +} // namespace android + +#endif /* HDCP_CONTROL_H */ diff --git a/merrifield/ips/common/OverlayHardware.h b/merrifield/ips/common/OverlayHardware.h new file mode 100644 index 0000000..a06f304 --- /dev/null +++ b/merrifield/ips/common/OverlayHardware.h @@ -0,0 +1,160 @@ +/* +// 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. +*/ +#ifndef OVERLAY_HARDWARE_H +#define OVERLAY_HARDWARE_H + +namespace android { +namespace intel { + +// only one overlay data buffer for testing +#define INTEL_OVERLAY_BUFFER_NUM 1 +#define INTEL_OVERLAY_MAX_WIDTH 2048 +#define INTEL_OVERLAY_MAX_HEIGHT 2048 +#define INTEL_OVERLAY_MIN_STRIDE 512 +#define INTEL_OVERLAY_MAX_STRIDE_PACKED (8 * 1024) +#define INTEL_OVERLAY_MAX_STRIDE_LINEAR (4 * 1024) +#define INTEL_OVERLAY_MAX_SCALING_RATIO 7 + +// Polyphase filter coefficients +#define N_HORIZ_Y_TAPS 5 +#define N_VERT_Y_TAPS 3 +#define N_HORIZ_UV_TAPS 3 +#define N_VERT_UV_TAPS 3 +#define N_PHASES 17 +#define MAX_TAPS 5 + +// Filter cutoff frequency limits. +#define MIN_CUTOFF_FREQ 1.0 +#define MAX_CUTOFF_FREQ 3.0 + +// Overlay init micros +#define OVERLAY_INIT_CONTRAST 0x4b +#define OVERLAY_INIT_BRIGHTNESS -19 +#define OVERLAY_INIT_SATURATION 0x92 +#define OVERLAY_INIT_GAMMA0 0x080808 +#define OVERLAY_INIT_GAMMA1 0x101010 +#define OVERLAY_INIT_GAMMA2 0x202020 +#define OVERLAY_INIT_GAMMA3 0x404040 +#define OVERLAY_INIT_GAMMA4 0x808080 +#define OVERLAY_INIT_GAMMA5 0xc0c0c0 +#define OVERLAY_INIT_COLORKEY 0 +#define OVERLAY_INIT_COLORKEYMASK ((0x0 << 31) | (0X0 << 30)) +#define OVERLAY_INIT_CONFIG ((0x1 << 18) | (0x1 << 3)) + +// overlay register values +#define OVERLAY_FORMAT_MASK (0xf << 10) +#define OVERLAY_FORMAT_PACKED_YUV422 (0x8 << 10) +#define OVERLAY_FORMAT_PLANAR_NV12_1 (0x7 << 10) +#define OVERLAY_FORMAT_PLANAR_NV12_2 (0xb << 10) +#define OVERLAY_FORMAT_PLANAR_YUV420 (0xc << 10) +#define OVERLAY_FORMAT_PLANAR_YUV422 (0xd << 10) +#define OVERLAY_FORMAT_PLANAR_YUV41X (0xe << 10) + +#define OVERLAY_PACKED_ORDER_YUY2 (0x0 << 14) +#define OVERLAY_PACKED_ORDER_YVYU (0x1 << 14) +#define OVERLAY_PACKED_ORDER_UYVY (0x2 << 14) +#define OVERLAY_PACKED_ORDER_VYUY (0x3 << 14) +#define OVERLAY_PACKED_ORDER_MASK (0x3 << 14) + +#define OVERLAY_MEMORY_LAYOUT_TILED (0x1 << 19) +#define OVERLAY_MEMORY_LAYOUT_LINEAR (0x0 << 19) + +#define OVERLAY_MIRRORING_NORMAL (0x0 << 17) +#define OVERLAY_MIRRORING_HORIZONTAL (0x1 << 17) +#define OVERLAY_MIRRORING_VERTIACAL (0x2 << 17) +#define OVERLAY_MIRRORING_BOTH (0x3 << 17) + +#define BUF_TYPE (0x1<<5) +#define BUF_TYPE_FRAME (0x0<<5) +#define BUF_TYPE_FIELD (0x1<<5) +#define TEST_MODE (0x1<<4) +#define BUFFER_SELECT (0x3<<2) +#define BUFFER0 (0x0<<2) +#define BUFFER1 (0x1<<2) +#define FIELD_SELECT (0x1<<1) +#define FIELD0 (0x0<<1) +#define FIELD1 (0x1<<1) +#define OVERLAY_ENABLE 0x1 + + +// Overlay contorl registers +typedef struct { + uint32_t OBUF_0Y; + uint32_t OBUF_1Y; + uint32_t OBUF_0U; + uint32_t OBUF_0V; + uint32_t OBUF_1U; + uint32_t OBUF_1V; + uint32_t OSTRIDE; + uint32_t YRGB_VPH; + uint32_t UV_VPH; + uint32_t HORZ_PH; + uint32_t INIT_PHS; + uint32_t DWINPOS; + uint32_t DWINSZ; + uint32_t SWIDTH; + uint32_t SWIDTHSW; + uint32_t SHEIGHT; + uint32_t YRGBSCALE; + uint32_t UVSCALE; + uint32_t OCLRC0; + uint32_t OCLRC1; + uint32_t DCLRKV; + uint32_t DCLRKM; + uint32_t SCHRKVH; + uint32_t SCHRKVL; + uint32_t SCHRKEN; + uint32_t OCONFIG; + uint32_t OCMD; + uint32_t RESERVED1; + uint32_t OSTART_0Y; + uint32_t OSTART_1Y; + uint32_t OSTART_0U; + uint32_t OSTART_0V; + uint32_t OSTART_1U; + uint32_t OSTART_1V; + uint32_t OTILEOFF_0Y; + uint32_t OTILEOFF_1Y; + uint32_t OTILEOFF_0U; + uint32_t OTILEOFF_0V; + uint32_t OTILEOFF_1U; + uint32_t OTILEOFF_1V; + uint32_t FASTHSCALE; + uint32_t UVSCALEV; + + uint32_t RESERVEDC[(0x200 - 0xA8) / 4]; + uint16_t Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; + uint16_t RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES]; + uint16_t Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; + uint16_t RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES]; + uint16_t UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; + uint16_t RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES]; + uint16_t UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; + uint16_t RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; +} OverlayBackBufferBlk; + +typedef struct { + uint8_t sign; + uint16_t mantissa; + uint8_t exponent; +} coeffRec, *coeffPtr; + + +} // namespace intel +} // nam + + +#endif diff --git a/merrifield/ips/common/OverlayPlaneBase.cpp b/merrifield/ips/common/OverlayPlaneBase.cpp new file mode 100644 index 0000000..5987b50 --- /dev/null +++ b/merrifield/ips/common/OverlayPlaneBase.cpp @@ -0,0 +1,1310 @@ +/* +// 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 <PhysicalDevice.h> +#include <common/OverlayPlaneBase.h> +#include <common/TTMBufferMapper.h> +#include <common/GrallocSubBuffer.h> +#include <DisplayQuery.h> + + +// FIXME: remove it +#include <OMX_IVCommon.h> +#include <OMX_IntelVideoExt.h> + +namespace android { +namespace intel { + +OverlayPlaneBase::OverlayPlaneBase(int index, int disp) + : DisplayPlane(index, PLANE_OVERLAY, disp), + mTTMBuffers(), + mActiveTTMBuffers(), + mCurrent(0), + mWsbm(0), + mPipeConfig(0), + mBobDeinterlace(0), + mUseScaledBuffer(0) +{ + CTRACE(); + for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { + mBackBuffer[i] = 0; + } +} + +OverlayPlaneBase::~OverlayPlaneBase() +{ + CTRACE(); +} + +bool OverlayPlaneBase::initialize(uint32_t bufferCount) +{ + Drm *drm = Hwcomposer::getInstance().getDrm(); + CTRACE(); + + // NOTE: use overlay's data buffer count for the overlay plane + if (bufferCount < OVERLAY_DATA_BUFFER_COUNT) { + ITRACE("override overlay buffer count from %d to %d", + bufferCount, OVERLAY_DATA_BUFFER_COUNT); + bufferCount = OVERLAY_DATA_BUFFER_COUNT; + } + if (!DisplayPlane::initialize(bufferCount)) { + DEINIT_AND_RETURN_FALSE("failed to initialize display plane"); + } + + mTTMBuffers.setCapacity(bufferCount); + mActiveTTMBuffers.setCapacity(MIN_DATA_BUFFER_COUNT); + + // init wsbm + mWsbm = new Wsbm(drm->getDrmFd()); + if (!mWsbm || !mWsbm->initialize()) { + DEINIT_AND_RETURN_FALSE("failed to create wsbm"); + } + + // create overlay back buffer + for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { + mBackBuffer[i] = createBackBuffer(); + if (!mBackBuffer[i]) { + DEINIT_AND_RETURN_FALSE("failed to create overlay back buffer"); + } + // reset back buffer + resetBackBuffer(i); + } + + // disable overlay when created + flush(PLANE_DISABLE); + + return true; +} + +bool OverlayPlaneBase::isDisabled() +{ + RETURN_FALSE_IF_NOT_INIT(); + + struct drm_psb_register_rw_arg arg; + memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); + + arg.get_plane_state_mask = 1; + arg.plane.type = DC_OVERLAY_PLANE; + arg.plane.index = mIndex; + // pass the pipe index to check its enabled status + // now we can pass the device id directly since + // their values are just equal + arg.plane.ctx = mDevice; // not used in kernel + + Drm *drm = Hwcomposer::getInstance().getDrm(); + bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); + if (ret == false) { + WTRACE("overlay plane query failed with error code %d", ret); + return false; + } + + DTRACE("overlay %d status %s on device %d, current device %d", + mIndex, arg.plane.ctx ? "DISABLED" : "ENABLED", mDevice, mDevice); + + return arg.plane.ctx == PSB_DC_PLANE_DISABLED; +} + +void OverlayPlaneBase::deinitialize() +{ + if (mTTMBuffers.size()) { + invalidateBufferCache(); + } + + if (mActiveTTMBuffers.size() > 0) { + invalidateActiveTTMBuffers(); + } + + // delete back buffer + for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { + if (mBackBuffer[i]) { + deleteBackBuffer(i); + mBackBuffer[i] = NULL; + } + } + DEINIT_AND_DELETE_OBJ(mWsbm); + + DisplayPlane::deinitialize(); +} + +void OverlayPlaneBase::invalidateBufferCache() +{ + // clear plane buffer cache + DisplayPlane::invalidateBufferCache(); + invalidateTTMBuffers(); +} + +bool OverlayPlaneBase::assignToDevice(int disp) +{ + uint32_t pipeConfig = 0; + + RETURN_FALSE_IF_NOT_INIT(); + VTRACE("overlay %d assigned to disp %d", mIndex, disp); + + switch (disp) { + case IDisplayDevice::DEVICE_EXTERNAL: + pipeConfig = (0x2 << 6); + break; + case IDisplayDevice::DEVICE_PRIMARY: + default: + pipeConfig = 0; + break; + } + + // if pipe switching happened, then disable overlay first + if (mPipeConfig != pipeConfig) { + DTRACE("overlay %d switched from %d to %d", mIndex, mDevice, disp); + disable(); + } + + mPipeConfig = pipeConfig; + DisplayPlane::assignToDevice(disp); + + enable(); + + return true; +} + +void OverlayPlaneBase::setZOrderConfig(ZOrderConfig& zorderConfig, + void *nativeConfig) +{ + CTRACE(); + + // setup overlay z order + int ovaZOrder = -1; + int ovcZOrder = -1; + for (size_t i = 0; i < zorderConfig.size(); i++) { + DisplayPlane *plane = zorderConfig[i]->plane; + if (plane->getType() == DisplayPlane::PLANE_OVERLAY) { + if (plane->getIndex() == 0) { + ovaZOrder = i; + } else if (plane->getIndex() == 1) { + ovcZOrder = i; + } + } + } + + for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { + OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf; + if (!backBuffer) + return; + + // force overlay c above overlay a + if ((ovaZOrder >= 0) && (ovaZOrder < ovcZOrder)) { + backBuffer->OCONFIG |= (1 << 15); + } else { + backBuffer->OCONFIG &= ~(1 << 15); + } + } +} + +bool OverlayPlaneBase::reset() +{ + RETURN_FALSE_IF_NOT_INIT(); + + DisplayPlane::reset(); + + // invalidate active TTM buffers + if (mActiveTTMBuffers.size() > 0) { + invalidateActiveTTMBuffers(); + } + + // reset back buffers + for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { + resetBackBuffer(i); + } + return true; +} + +bool OverlayPlaneBase::enable() +{ + RETURN_FALSE_IF_NOT_INIT(); + for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { + OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf; + if (!backBuffer) + return false; + + if (backBuffer->OCMD & 0x1) + return true; + + backBuffer->OCMD |= 0x1; + } + + // flush + flush(PLANE_ENABLE); + return true; +} + +bool OverlayPlaneBase::disable() +{ + RETURN_FALSE_IF_NOT_INIT(); + for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { + OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf; + if (!backBuffer) + return false; + + if (!(backBuffer->OCMD & 0x1)) + return true; + + backBuffer->OCMD &= ~0x1; + } + + // flush + flush(PLANE_DISABLE); + return true; +} + +OverlayBackBuffer* OverlayPlaneBase::createBackBuffer() +{ + CTRACE(); + + // create back buffer + OverlayBackBuffer *backBuffer = (OverlayBackBuffer *)malloc(sizeof(OverlayBackBuffer)); + if (!backBuffer) { + ETRACE("failed to allocate back buffer"); + return 0; + } + + + int size = sizeof(OverlayBackBufferBlk); + int alignment = 64 * 1024; + void *wsbmBufferObject = 0; + bool ret = mWsbm->allocateTTMBuffer(size, alignment, &wsbmBufferObject); + if (ret == false) { + ETRACE("failed to allocate TTM buffer"); + return 0; + } + + void *virtAddr = mWsbm->getCPUAddress(wsbmBufferObject); + uint32_t gttOffsetInPage = mWsbm->getGttOffset(wsbmBufferObject); + + backBuffer->buf = (OverlayBackBufferBlk *)virtAddr; + backBuffer->gttOffsetInPage = gttOffsetInPage; + backBuffer->bufObject = wsbmBufferObject; + + VTRACE("cpu %p, gtt %d", virtAddr, gttOffsetInPage); + + return backBuffer; +} + +void OverlayPlaneBase::deleteBackBuffer(int buf) +{ + if (!mBackBuffer[buf]) + return; + + void *wsbmBufferObject = mBackBuffer[buf]->bufObject; + bool ret = mWsbm->destroyTTMBuffer(wsbmBufferObject); + if (ret == false) { + WTRACE("failed to destroy TTM buffer"); + } + // free back buffer + free(mBackBuffer[buf]); + mBackBuffer[buf] = 0; +} + +void OverlayPlaneBase::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 << 3); + backBuffer->OCONFIG |= (0x1 << 27); + backBuffer->SCHRKEN &= ~(0x7 << 24); + backBuffer->SCHRKEN |= 0xff; +} + +BufferMapper* OverlayPlaneBase::getTTMMapper(BufferMapper& grallocMapper, struct VideoPayloadBuffer *payload) +{ + buffer_handle_t khandle; + uint32_t w, h; + uint32_t yStride, uvStride; + stride_t stride; + int srcX, srcY, srcW, srcH; + int tmp; + + DataBuffer *buf; + ssize_t index; + TTMBufferMapper *mapper; + bool ret; + + if (!payload) { + ETRACE("invalid payload buffer"); + return 0; + } + + srcX = grallocMapper.getCrop().x; + srcY = grallocMapper.getCrop().y; + srcW = grallocMapper.getCrop().w; + srcH = grallocMapper.getCrop().h; + + // init ttm buffer + if (mUseScaledBuffer) { + khandle = payload->scaling_khandle; + } else { + khandle = payload->rotated_buffer_handle; + } + index = mTTMBuffers.indexOfKey(khandle); + if (index < 0) { + VTRACE("unmapped TTM buffer, will map it"); + + if (mUseScaledBuffer) { + w = payload->scaling_width; + h = payload->scaling_height; + } else { + w = payload->rotated_width; + h = payload->rotated_height; + + checkCrop(srcX, srcY, srcW, srcH, payload->coded_width, payload->coded_height); + } + + uint32_t format = grallocMapper.getFormat(); + // this is for sw decode with tiled buffer in landscape mode + if (payload->tiling) + format = OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled; + + // calculate stride + switch (format) { + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_I420: + uint32_t yStride_align; + yStride_align = DisplayQuery::getOverlayLumaStrideAlignment(grallocMapper.getFormat()); + if (yStride_align > 0) + { + yStride = align_to(align_to(w, 32), yStride_align); + } + else + { + yStride = align_to(align_to(w, 32), 64); + } + uvStride = align_to(yStride >> 1, 64); + stride.yuv.yStride = yStride; + stride.yuv.uvStride = uvStride; + break; + case HAL_PIXEL_FORMAT_NV12: + yStride = align_to(align_to(w, 32), 64); + uvStride = yStride; + stride.yuv.yStride = yStride; + stride.yuv.uvStride = uvStride; + break; + case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: + case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: + if (mUseScaledBuffer) { + stride.yuv.yStride = payload->scaling_luma_stride; + stride.yuv.uvStride = payload->scaling_chroma_u_stride; + } else { + yStride = align_to(align_to(w, 32), 64); + uvStride = yStride; + stride.yuv.yStride = yStride; + stride.yuv.uvStride = uvStride; + } + break; + case HAL_PIXEL_FORMAT_YUY2: + case HAL_PIXEL_FORMAT_UYVY: + yStride = align_to((align_to(w, 32) << 1), 64); + uvStride = 0; + stride.yuv.yStride = yStride; + stride.yuv.uvStride = uvStride; + break; + } + + DataBuffer buf(khandle); + // update buffer + buf.setStride(stride); + buf.setWidth(w); + buf.setHeight(h); + buf.setCrop(srcX, srcY, srcW, srcH); + buf.setFormat(format); + + // create buffer mapper + bool res = false; + do { + mapper = new TTMBufferMapper(*mWsbm, buf); + if (!mapper) { + ETRACE("failed to allocate mapper"); + break; + } + // map ttm buffer + ret = mapper->map(); + if (!ret) { + ETRACE("failed to map"); + invalidateTTMBuffers(); + ret = mapper->map(); + if (!ret) { + ETRACE("failed to remap"); + break; + } + } + + if (mTTMBuffers.size() >= OVERLAY_DATA_BUFFER_COUNT) { + invalidateTTMBuffers(); + } + + // add mapper + index = mTTMBuffers.add(khandle, mapper); + if (index < 0) { + ETRACE("failed to add TTMMapper"); + break; + } + + // increase mapper refCount since it is added to mTTMBuffers + mapper->incRef(); + res = true; + } while (0); + + if (!res) { + // error handling + if (mapper) { + mapper->unmap(); + delete mapper; + mapper = NULL; + } + return 0; + } + } else { + VTRACE("got mapper in saved ttm buffers"); + mapper = reinterpret_cast<TTMBufferMapper *>(mTTMBuffers.valueAt(index)); + if (mapper->getCrop().x != srcX || mapper->getCrop().y != srcY || + mapper->getCrop().w != srcW || mapper->getCrop().h != srcH) { + if(!mUseScaledBuffer) + checkCrop(srcX, srcY, srcW, srcH, payload->coded_width, payload->coded_height); + mapper->setCrop(srcX, srcY, srcW, srcH); + } + } + + XTRACE(); + return mapper; +} + +void OverlayPlaneBase::putTTMMapper(BufferMapper* mapper) +{ + if (!mapper) + return; + + if (!mapper->decRef()) { + // unmap it + mapper->unmap(); + + // destroy this mapper + delete mapper; + } +} + +bool OverlayPlaneBase::isActiveTTMBuffer(BufferMapper *mapper) +{ + for (size_t i = 0; i < mActiveTTMBuffers.size(); i++) { + BufferMapper *activeMapper = mActiveTTMBuffers.itemAt(i); + if (!activeMapper) + continue; + if (activeMapper->getKey() == mapper->getKey()) + return true; + } + + return false; +} + +void OverlayPlaneBase::updateActiveTTMBuffers(BufferMapper *mapper) +{ + // unmap the first entry (oldest buffer) + if (mActiveTTMBuffers.size() >= MAX_ACTIVE_TTM_BUFFERS) { + BufferMapper *oldest = mActiveTTMBuffers.itemAt(0); + putTTMMapper(oldest); + mActiveTTMBuffers.removeAt(0); + } + + // queue it to cached buffers + if (!isActiveTTMBuffer(mapper)) { + mapper->incRef(); + mActiveTTMBuffers.push_back(mapper); + } +} + +void OverlayPlaneBase::invalidateActiveTTMBuffers() +{ + BufferMapper* mapper; + + RETURN_VOID_IF_NOT_INIT(); + + for (size_t i = 0; i < mActiveTTMBuffers.size(); i++) { + mapper = mActiveTTMBuffers.itemAt(i); + // unmap it + putTTMMapper(mapper); + } + + // clear recorded data buffers + mActiveTTMBuffers.clear(); +} + +void OverlayPlaneBase::invalidateTTMBuffers() +{ + BufferMapper* mapper; + for (size_t i = 0; i < mTTMBuffers.size(); i++) { + mapper = mTTMBuffers.valueAt(i); + // putTTMMapper removes mapper from cache + putTTMMapper(mapper); + } + mTTMBuffers.clear(); +} + + +bool OverlayPlaneBase::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) + 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) + return false; + + if (payload->client_transform != mTransform) { + if (payload->surface_protected) { + payload->hwc_timestamp = systemTime(); + payload->layer_transform = mTransform; + } + WTRACE("client is not ready"); + return false; + } + + rotatedMapper = getTTMMapper(mapper, payload); + return true; +} + + +bool OverlayPlaneBase::useOverlayRotation(BufferMapper& mapper) +{ + // by default overlay plane does not support rotation. + return false; +} + +bool OverlayPlaneBase::scaledBufferReady(BufferMapper& mapper, BufferMapper* &scaledMapper, VideoPayloadBuffer *payload) +{ + return false; +} + +void OverlayPlaneBase::checkPosition(int& x, int& y, int& w, int& h) +{ + drmModeModeInfoPtr mode = &mModeInfo; + + if (mode->hdisplay == 0 || mode->vdisplay == 0) + return; + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + if ((x + w) > mode->hdisplay) + w = mode->hdisplay - x; + if ((y + h) > mode->vdisplay) + h = mode->vdisplay - y; +} + +void OverlayPlaneBase::checkCrop(int& srcX, int& srcY, int& srcW, int& srcH, + int coded_width, int coded_height) +{ + int tmp; + + if (mTransform) + srcH >>= mBobDeinterlace; + + if (mTransform == HWC_TRANSFORM_ROT_90 || mTransform == HWC_TRANSFORM_ROT_270) { + tmp = srcH; + srcH = srcW; + srcW = tmp; + + tmp = srcX; + srcX = srcY; + srcY = tmp; + + tmp = coded_width; + coded_width = coded_height; + coded_height = tmp; + } + + // skip pading bytes in rotate buffer + switch(mTransform) { + case HWC_TRANSFORM_ROT_90: + srcX = (coded_width >> mBobDeinterlace) - srcW - srcX; + break; + case HWC_TRANSFORM_ROT_180: + srcX = coded_width - srcW - srcX; + srcY = (coded_height >> mBobDeinterlace) - srcH - srcY; + break; + case HWC_TRANSFORM_ROT_270: + srcY = coded_height - srcH - srcY; + break; + default: + break; + } +} + + +bool OverlayPlaneBase::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; + + // clear original format setting + backBuffer->OCMD &= ~(0xf << 10); + backBuffer->OCMD &= ~OVERLAY_MEMORY_LAYOUT_TILED; + + // Y/U/V plane must be 4k bytes aligned. + backBuffer->OSTART_0Y = 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 + backBuffer->OSTART_0Y |= 0x01; + } + + backBuffer->OSTART_0U = gttOffsetInBytes; + backBuffer->OSTART_0V = gttOffsetInBytes; + + backBuffer->OSTART_1Y = backBuffer->OSTART_0Y; + backBuffer->OSTART_1U = backBuffer->OSTART_0U; + backBuffer->OSTART_1V = backBuffer->OSTART_0V; + + switch(format) { + case HAL_PIXEL_FORMAT_YV12: // YV12 + backBuffer->OBUF_0Y = 0; + backBuffer->OBUF_0V = yStride * h; + backBuffer->OBUF_0U = backBuffer->OBUF_0V + (uvStride * (h / 2)); + backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420; + break; + case HAL_PIXEL_FORMAT_I420: // I420 + backBuffer->OBUF_0Y = 0; + backBuffer->OBUF_0U = yStride * h; + backBuffer->OBUF_0V = backBuffer->OBUF_0U + (uvStride * (h / 2)); + backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420; + break; + case HAL_PIXEL_FORMAT_NV12: // NV12 + backBuffer->OBUF_0Y = 0; + backBuffer->OBUF_0U = yStride * h; + backBuffer->OBUF_0V = 0; + 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: // Intel codec NV12 + backBuffer->OBUF_0Y = 0; + backBuffer->OBUF_0U = yStride * align_to(h, 32); + backBuffer->OBUF_0V = 0; + backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; + break; + case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: //NV12_tiled + backBuffer->OBUF_0Y = 0; + backBuffer->OBUF_0U = yStride * align_to(h, 32); + backBuffer->OBUF_0V = 0; + backBuffer->OSTART_0U += yStride * align_to(h, 32); + backBuffer->OSTART_0V += yStride * align_to(h, 32); + backBuffer->OSTART_1U = backBuffer->OSTART_0U; + backBuffer->OSTART_1V = backBuffer->OSTART_0V; + backBuffer->OTILEOFF_0Y = srcX + (srcY << 16); + backBuffer->OTILEOFF_1Y = backBuffer->OTILEOFF_0Y; + backBuffer->OTILEOFF_0U = srcX + ((srcY / 2) << 16); + backBuffer->OTILEOFF_1U = backBuffer->OTILEOFF_0U; + backBuffer->OTILEOFF_0V = backBuffer->OTILEOFF_0U; + backBuffer->OTILEOFF_1V = backBuffer->OTILEOFF_0U; + backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; + backBuffer->OCMD |= OVERLAY_MEMORY_LAYOUT_TILED; + break; + case HAL_PIXEL_FORMAT_YUY2: // YUY2 + backBuffer->OBUF_0Y = 0; + backBuffer->OBUF_0U = 0; + backBuffer->OBUF_0V = 0; + backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422; + backBuffer->OCMD |= OVERLAY_PACKED_ORDER_YUY2; + break; + case HAL_PIXEL_FORMAT_UYVY: // UYVY + backBuffer->OBUF_0Y = 0; + backBuffer->OBUF_0U = 0; + backBuffer->OBUF_0V = 0; + backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422; + backBuffer->OCMD |= OVERLAY_PACKED_ORDER_UYVY; + break; + default: + ETRACE("unsupported format %d", format); + return false; + } + + backBuffer->OBUF_0Y += srcY * yStride + srcX; + backBuffer->OBUF_0V += (srcY / 2) * uvStride + srcX; + backBuffer->OBUF_0U += (srcY / 2) * uvStride + srcX; + backBuffer->OBUF_1Y = backBuffer->OBUF_0Y; + backBuffer->OBUF_1U = backBuffer->OBUF_0U; + backBuffer->OBUF_1V = backBuffer->OBUF_0V; + + VTRACE("done. offset (%d, %d, %d)", + backBuffer->OBUF_0Y, + backBuffer->OBUF_0U, + backBuffer->OBUF_0V); + return true; +} + +uint32_t OverlayPlaneBase::calculateSWidthSW(uint32_t offset, uint32_t width) +{ + ATRACE("offset = %d, width = %d", offset, width); + + uint32_t swidth = ((offset + width + 0x3F) >> 6) - (offset >> 6); + + swidth <<= 1; + swidth -= 1; + + return swidth; +} + +bool OverlayPlaneBase::coordinateSetup(BufferMapper& mapper) +{ + CTRACE(); + + OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; + if (!backBuffer) { + ETRACE("invalid back buffer"); + return false; + } + + uint32_t swidthy = 0; + uint32_t swidthuv = 0; + uint32_t format = mapper.getFormat(); + uint32_t width = mapper.getCrop().w; + uint32_t height = mapper.getCrop().h; + uint32_t yStride = mapper.getStride().yuv.yStride; + uint32_t uvStride = mapper.getStride().yuv.uvStride; + uint32_t offsety = backBuffer->OBUF_0Y; + uint32_t offsetu = backBuffer->OBUF_0U; + + switch (format) { + case HAL_PIXEL_FORMAT_YV12: // YV12 + case HAL_PIXEL_FORMAT_I420: // I420 + case HAL_PIXEL_FORMAT_NV12: // NV12 + case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: // NV12 + case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: // NV12_tiled + break; + case HAL_PIXEL_FORMAT_YUY2: // YUY2 + case HAL_PIXEL_FORMAT_UYVY: // UYVY + width <<= 1; + break; + default: + ETRACE("unsupported format %d", format); + return false; + } + + if (width <= 0 || height <= 0) { + ETRACE("invalid src dim"); + return false; + } + + if (yStride <=0 && uvStride <= 0) { + ETRACE("invalid source stride"); + return false; + } + + backBuffer->SWIDTH = width | ((width / 2) << 16); + swidthy = calculateSWidthSW(offsety, width); + swidthuv = calculateSWidthSW(offsetu, width / 2); + backBuffer->SWIDTHSW = (swidthy << 2) | (swidthuv << 18); + backBuffer->SHEIGHT = height | ((height / 2) << 16); + backBuffer->OSTRIDE = (yStride & (~0x3f)) | ((uvStride & (~0x3f)) << 16); + + XTRACE(); + + return true; +} + +bool OverlayPlaneBase::setCoeffRegs(double *coeff, int mantSize, + coeffPtr pCoeff, int pos) +{ + int maxVal, icoeff, res; + int sign; + double c; + + sign = 0; + maxVal = 1 << mantSize; + c = *coeff; + if (c < 0.0) { + sign = 1; + c = -c; + } + + res = 12 - mantSize; + if ((icoeff = (int)(c * 4 * maxVal + 0.5)) < maxVal) { + pCoeff[pos].exponent = 3; + pCoeff[pos].mantissa = icoeff << res; + *coeff = (double)icoeff / (double)(4 * maxVal); + } else if ((icoeff = (int)(c * 2 * maxVal + 0.5)) < maxVal) { + pCoeff[pos].exponent = 2; + pCoeff[pos].mantissa = icoeff << res; + *coeff = (double)icoeff / (double)(2 * maxVal); + } else if ((icoeff = (int)(c * maxVal + 0.5)) < maxVal) { + pCoeff[pos].exponent = 1; + pCoeff[pos].mantissa = icoeff << res; + *coeff = (double)icoeff / (double)(maxVal); + } else if ((icoeff = (int)(c * maxVal * 0.5 + 0.5)) < maxVal) { + pCoeff[pos].exponent = 0; + pCoeff[pos].mantissa = icoeff << res; + *coeff = (double)icoeff / (double)(maxVal / 2); + } else { + // Coeff out of range + return false; + } + + pCoeff[pos].sign = sign; + if (sign) + *coeff = -(*coeff); + return true; +} + +void OverlayPlaneBase::updateCoeff(int taps, double fCutoff, + bool isHoriz, bool isY, + coeffPtr pCoeff) +{ + int i, j, j1, num, pos, mantSize; + double pi = 3.1415926535, val, sinc, window, sum; + double rawCoeff[MAX_TAPS * 32], coeffs[N_PHASES][MAX_TAPS]; + double diff; + int tapAdjust[MAX_TAPS], tap2Fix; + bool isVertAndUV; + + if (isHoriz) + mantSize = 7; + else + mantSize = 6; + + isVertAndUV = !isHoriz && !isY; + num = taps * 16; + for (i = 0; i < num * 2; i++) { + val = (1.0 / fCutoff) * taps * pi * (i - num) / (2 * num); + if (val == 0.0) + sinc = 1.0; + else + sinc = sin(val) / val; + + // Hamming window + window = (0.54 - 0.46 * cos(2 * i * pi / (2 * num - 1))); + rawCoeff[i] = sinc * window; + } + + for (i = 0; i < N_PHASES; i++) { + // Normalise the coefficients + sum = 0.0; + for (j = 0; j < taps; j++) { + pos = i + j * 32; + sum += rawCoeff[pos]; + } + for (j = 0; j < taps; j++) { + pos = i + j * 32; + coeffs[i][j] = rawCoeff[pos] / sum; + } + + // Set the register values + for (j = 0; j < taps; j++) { + pos = j + i * taps; + if ((j == (taps - 1) / 2) && !isVertAndUV) + setCoeffRegs(&coeffs[i][j], mantSize + 2, pCoeff, pos); + else + setCoeffRegs(&coeffs[i][j], mantSize, pCoeff, pos); + } + + tapAdjust[0] = (taps - 1) / 2; + for (j = 1, j1 = 1; j <= tapAdjust[0]; j++, j1++) { + tapAdjust[j1] = tapAdjust[0] - j; + tapAdjust[++j1] = tapAdjust[0] + j; + } + + // Adjust the coefficients + sum = 0.0; + for (j = 0; j < taps; j++) + sum += coeffs[i][j]; + if (sum != 1.0) { + for (j1 = 0; j1 < taps; j1++) { + tap2Fix = tapAdjust[j1]; + diff = 1.0 - sum; + coeffs[i][tap2Fix] += diff; + pos = tap2Fix + i * taps; + if ((tap2Fix == (taps - 1) / 2) && !isVertAndUV) + setCoeffRegs(&coeffs[i][tap2Fix], mantSize + 2, pCoeff, pos); + else + setCoeffRegs(&coeffs[i][tap2Fix], mantSize, pCoeff, pos); + + sum = 0.0; + for (j = 0; j < taps; j++) + sum += coeffs[i][j]; + if (sum == 1.0) + break; + } + } + } +} + +bool OverlayPlaneBase::scalingSetup(BufferMapper& mapper) +{ + int xscaleInt, xscaleFract, yscaleInt, yscaleFract; + int xscaleIntUV, xscaleFractUV; + int yscaleIntUV, yscaleFractUV; + int deinterlace_factor = 1; + // 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]; + int i, j, pos; + bool scaleChanged = false; + int x, y, w, h; + + OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; + if (!backBuffer) { + ETRACE("invalid back buffer"); + return false; + } + + 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)", + srcWidth, srcHeight, + dstWidth, dstHeight); + + // 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 fCutoffY; + double fCutoffUV; + + fCutoffY = xscaleFract / 4096.0; + fCutoffUV = xscaleFractUV / 4096.0; + + // Limit to between 1.0 and 3.0 + if (fCutoffY < MIN_CUTOFF_FREQ) + fCutoffY = MIN_CUTOFF_FREQ; + if (fCutoffY > MAX_CUTOFF_FREQ) + fCutoffY = MAX_CUTOFF_FREQ; + if (fCutoffUV < MIN_CUTOFF_FREQ) + fCutoffUV = MIN_CUTOFF_FREQ; + if (fCutoffUV > MAX_CUTOFF_FREQ) + fCutoffUV = MAX_CUTOFF_FREQ; + + updateCoeff(N_HORIZ_Y_TAPS, fCutoffY, true, true, xcoeffY); + updateCoeff(N_HORIZ_UV_TAPS, fCutoffUV, true, false, xcoeffUV); + + 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); + } + } + } + + XTRACE(); + return true; +} + +bool OverlayPlaneBase::colorSetup(BufferMapper& mapper) +{ + CTRACE(); + + OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; + if (!backBuffer) { + ETRACE("invalid back buffer"); + return false; + } + + uint32_t format = mapper.getFormat(); + if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar && + format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) { + + VTRACE("Not video layer, use default color setting"); + backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) | + (OVERLAY_INIT_BRIGHTNESS & 0xff); + backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION; + backBuffer->OCONFIG &= ~(1 << 5); + + return true; + } + + struct VideoPayloadBuffer *payload; + payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1); + // check payload + if (!payload) { + ETRACE("no payload found"); + return false; + } + + // BT.601 or BT.709 + backBuffer->OCONFIG &= ~(1 << 5); + backBuffer->OCONFIG |= ((payload->csc_mode & 1) << 5); + + // no level expansion for video on HDMI + if (payload->video_range || mPipeConfig == (0x2 << 6)) { + // full range, no need to do level expansion + backBuffer->OCLRC0 = 0x1000000; + backBuffer->OCLRC1 = 0x80; + } else { + // level expansion for limited range + backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) | + (OVERLAY_INIT_BRIGHTNESS & 0xff); + backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION; + } + + return true; +} + +bool OverlayPlaneBase::setDataBuffer(BufferMapper& grallocMapper) +{ + BufferMapper *mapper; + BufferMapper *videoBufferMapper = 0; + bool ret; + uint32_t format; + + RETURN_FALSE_IF_NOT_INIT(); + + // get gralloc mapper + mapper = &grallocMapper; + format = grallocMapper.getFormat(); + if (format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar || + format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) { + struct VideoPayloadBuffer *payload; + payload = (struct VideoPayloadBuffer *)grallocMapper.getCpuAddress(SUB_BUFFER1); + if (!payload) { + ETRACE("invalid payload buffer"); + return 0; + } + + mBobDeinterlace = payload->bob_deinterlace; + + int srcW, srcH; + srcW = grallocMapper.getCrop().w - grallocMapper.getCrop().x; + srcH = grallocMapper.getCrop().h - grallocMapper.getCrop().y; + if ((srcW > INTEL_OVERLAY_MAX_WIDTH - 1) || (srcH > INTEL_OVERLAY_MAX_HEIGHT - 1)) { + if (mTransform) { + int x, y, w, h; + x = mSrcCrop.x; + y = mSrcCrop.y; + w = mSrcCrop.w; + h = mSrcCrop.h; + setSourceCrop(0, 0, payload->scaling_width, payload->scaling_height); + if (!useOverlayRotation(grallocMapper)) { + DTRACE("The scaled buffer will hit overlay rotation limitation, fall back to GLES"); + setSourceCrop(x, y, w, h); + return false; + } + } + + if (!scaledBufferReady(grallocMapper, videoBufferMapper, payload)) { + DTRACE("scaled buffer is not ready, fall back to GLES"); + return false; + } else { + videoBufferMapper->setFormat(OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar); + mapper = videoBufferMapper; + } + } + } + + if (!mUseScaledBuffer && mTransform && !useOverlayRotation(grallocMapper)) { + if (!rotatedBufferReady(grallocMapper, videoBufferMapper)) { + DTRACE("rotated buffer is not ready"); + return false; + } + + if (!videoBufferMapper) { + ETRACE("failed to get rotated buffer"); + return false; + } + mapper = videoBufferMapper; + } + + OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; + if (!backBuffer) { + ETRACE("invalid back buffer"); + return false; + } + + ret = bufferOffsetSetup(*mapper); + if (ret == false) { + ETRACE("failed to set up buffer offsets"); + return false; + } + + ret = coordinateSetup(*mapper); + if (ret == false) { + ETRACE("failed to set up overlay coordinates"); + return false; + } + + ret = scalingSetup(*mapper); + if (ret == false) { + ETRACE("failed to set up scaling parameters"); + return false; + } + + backBuffer->OCMD |= 0x1; + + ret = colorSetup(grallocMapper); + if (ret == false) { + ETRACE("failed to set up color parameters"); + return false; + } + if (mBobDeinterlace && !mTransform) { + backBuffer->OCMD |= BUF_TYPE_FIELD; + backBuffer->OCMD &= ~FIELD_SELECT; + backBuffer->OCMD |= FIELD0; + backBuffer->OCMD &= ~(BUFFER_SELECT); + backBuffer->OCMD |= BUFFER0; + } + + // add to active ttm buffers if it's a rotated buffer + if (videoBufferMapper) { + updateActiveTTMBuffers(mapper); + } + + mUseScaledBuffer = 0; + return true; +} + +} // namespace intel +} // namespace android + diff --git a/merrifield/ips/common/OverlayPlaneBase.h b/merrifield/ips/common/OverlayPlaneBase.h new file mode 100644 index 0000000..fc76a61 --- /dev/null +++ b/merrifield/ips/common/OverlayPlaneBase.h @@ -0,0 +1,129 @@ +/* +// 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. +*/ +#ifndef OVERLAY_PLANE_BASE_H +#define OVERLAY_PLANE_BASE_H + +#include <utils/KeyedVector.h> +#include <hal_public.h> +#include <DisplayPlane.h> +#include <BufferMapper.h> +#include <common/Wsbm.h> +#include <common/OverlayHardware.h> +#include <common/VideoPayloadBuffer.h> + +namespace android { +namespace intel { + +typedef struct { + OverlayBackBufferBlk *buf; + uint32_t gttOffsetInPage; + void* bufObject; +} OverlayBackBuffer; + +class OverlayPlaneBase : public DisplayPlane { +public: + OverlayPlaneBase(int index, int disp); + virtual ~OverlayPlaneBase(); + + virtual void invalidateBufferCache(); + + virtual bool assignToDevice(int disp); + + virtual void setZOrderConfig(ZOrderConfig& config, void *nativeConfig); + + // plane operations + virtual bool flip(void *ctx) = 0; + virtual bool reset(); + virtual bool enable(); + virtual bool disable(); + virtual bool isDisabled(); + + virtual void* getContext() const = 0; + virtual bool initialize(uint32_t bufferCount); + virtual void deinitialize(); + +protected: + // generic overlay register flush + virtual bool flush(uint32_t flags) = 0; + virtual bool setDataBuffer(BufferMapper& mapper); + virtual bool bufferOffsetSetup(BufferMapper& mapper); + virtual uint32_t calculateSWidthSW(uint32_t offset, uint32_t width); + virtual bool coordinateSetup(BufferMapper& mapper); + virtual bool setCoeffRegs(double *coeff, int mantSize, + coeffPtr pCoeff, int pos); + virtual void updateCoeff(int taps, double fCutoff, + bool isHoriz, bool isY, + coeffPtr pCoeff); + virtual bool scalingSetup(BufferMapper& mapper); + virtual bool colorSetup(BufferMapper& mapper); + virtual void checkPosition(int& x, int& y, int& w, int& h); + virtual void checkCrop(int& x, int& y, int& w, int& h, int coded_width, int coded_height); + + +protected: + // back buffer operations + virtual OverlayBackBuffer* createBackBuffer(); + virtual void deleteBackBuffer(int buf); + virtual void resetBackBuffer(int buf); + + virtual BufferMapper* getTTMMapper(BufferMapper& grallocMapper, struct VideoPayloadBuffer *payload); + virtual void putTTMMapper(BufferMapper* mapper); + virtual bool rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper); + virtual bool useOverlayRotation(BufferMapper& mapper); + virtual bool scaledBufferReady(BufferMapper& mapper, BufferMapper* &scaledMapper, VideoPayloadBuffer *payload); + +private: + inline bool isActiveTTMBuffer(BufferMapper *mapper); + void updateActiveTTMBuffers(BufferMapper *mapper); + void invalidateActiveTTMBuffers(); + void invalidateTTMBuffers(); + +protected: + // flush flags + enum { + PLANE_ENABLE = 0x00000001UL, + PLANE_DISABLE = 0x00000002UL, + UPDATE_COEF = 0x00000004UL, + }; + + enum { + OVERLAY_BACK_BUFFER_COUNT = 3, + MAX_ACTIVE_TTM_BUFFERS = 3, + OVERLAY_DATA_BUFFER_COUNT = 20, + }; + + // TTM data buffers + KeyedVector<buffer_handle_t, BufferMapper*> mTTMBuffers; + // latest TTM buffers + Vector<BufferMapper*> mActiveTTMBuffers; + + // overlay back buffer + OverlayBackBuffer *mBackBuffer[OVERLAY_BACK_BUFFER_COUNT]; + int mCurrent; + // wsbm + Wsbm *mWsbm; + // pipe config + uint32_t mPipeConfig; + + int mBobDeinterlace; + int mUseScaledBuffer; +}; + +} // namespace intel +} // namespace android + +#endif /* OVERLAY_PLANE_BASE_H */ + diff --git a/merrifield/ips/common/PixelFormat.cpp b/merrifield/ips/common/PixelFormat.cpp new file mode 100644 index 0000000..758788c --- /dev/null +++ b/merrifield/ips/common/PixelFormat.cpp @@ -0,0 +1,55 @@ +/* +// 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 <hal_public.h> +#include <HwcTrace.h> +#include <common/PixelFormat.h> + +namespace android { +namespace intel { + +bool PixelFormat::convertFormat(uint32_t grallocFormat, uint32_t& spriteFormat, int& bpp) +{ + switch (grallocFormat) { + case HAL_PIXEL_FORMAT_RGBA_8888: + spriteFormat = PLANE_PIXEL_FORMAT_RGBA8888; + bpp = 4; + break; + case HAL_PIXEL_FORMAT_RGBX_8888: + spriteFormat = PLANE_PIXEL_FORMAT_RGBX8888; + bpp = 4; + break; + case HAL_PIXEL_FORMAT_BGRX_8888: + spriteFormat = PLANE_PIXEL_FORMAT_BGRX8888; + bpp = 4; + break; + case HAL_PIXEL_FORMAT_BGRA_8888: + spriteFormat = PLANE_PIXEL_FORMAT_BGRA8888; + bpp = 4; + break; + case HAL_PIXEL_FORMAT_RGB_565: + spriteFormat = PLANE_PIXEL_FORMAT_BGRX565; + bpp = 2; + break; + default: + return false; + } + + return true; +} + + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/common/PixelFormat.h b/merrifield/ips/common/PixelFormat.h new file mode 100644 index 0000000..cea69e0 --- /dev/null +++ b/merrifield/ips/common/PixelFormat.h @@ -0,0 +1,41 @@ +/* +// 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. +*/ +#ifndef PIXEL_FORMAT_H +#define PIXEL_FORMAT_H + +namespace android { +namespace intel { + +class PixelFormat +{ +public: + enum { + PLANE_PIXEL_FORMAT_BGRX565 = 0x14000000UL, + PLANE_PIXEL_FORMAT_BGRX8888 = 0x18000000UL, + PLANE_PIXEL_FORMAT_BGRA8888 = 0x1c000000UL, + PLANE_PIXEL_FORMAT_RGBX8888 = 0x38000000UL, + PLANE_PIXEL_FORMAT_RGBA8888 = 0x3c000000UL, + }; + + // convert gralloc color format to IP specific sprite pixel format. + // See DSPACNTR (Display A Primary Sprite Control Register for more information) + static bool convertFormat(uint32_t grallocFormat, uint32_t& spriteFormat, int& bpp); +}; + +} // namespace intel +} // namespace android + +#endif /*PIXEL_FORMAT_H*/ diff --git a/merrifield/ips/common/PlaneCapabilities.cpp b/merrifield/ips/common/PlaneCapabilities.cpp new file mode 100644 index 0000000..973c535 --- /dev/null +++ b/merrifield/ips/common/PlaneCapabilities.cpp @@ -0,0 +1,234 @@ +/* +// 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 "OverlayHardware.h" +#include <HwcLayer.h> + +#define SPRITE_PLANE_MAX_STRIDE_TILED 16384 +//FIXME: need confirmation about this stride +#define SPRITE_PLANE_MAX_STRIDE_LINEAR 8192 + +#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: + return trans ? false: true; + 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: + 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; + } + 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) { + bool ret = false; + + // support premultipled & none blanding + switch (blending) { + case HWC_BLENDING_NONE: + return true; + case HWC_BLENDING_PREMULT: + ret = false; + if ((planeAlpha == 0) || (planeAlpha == 255)) { + ret = true; + } + return ret; + 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; + + 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)) { + return false; + } + + if (dstW <= 1 || dstH <= 1 || srcW <= 1 || srcH <= 1) { + // Workaround: Overlay flip when height is 1 causes MIPI stall on TNG + return false; + } + + return true; + } else if (planeType == DisplayPlane::PLANE_CURSOR) { + if (srcW > 256 || srcH > 256) { + return false; + } + 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 + diff --git a/merrifield/ips/common/PrepareListener.cpp b/merrifield/ips/common/PrepareListener.cpp new file mode 100644 index 0000000..0b4b05d --- /dev/null +++ b/merrifield/ips/common/PrepareListener.cpp @@ -0,0 +1,50 @@ +/* +// 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 <Drm.h> +#include <Hwcomposer.h> +#include <common/PrepareListener.h> + +namespace android { +namespace intel { + +PrepareListener::PrepareListener() + : IPrepareListener() +{ +} + +PrepareListener::~PrepareListener() +{ +} + +void PrepareListener::onProtectedLayerStart(int disp) +{ + WTRACE("disp = %d, ignored for now", disp); + // need chaabi support for granular IED control + return; + + Drm *drm = Hwcomposer::getInstance().getDrm(); + int ret = drmCommandNone(drm->getDrmFd(), DRM_PSB_HDCP_DISPLAY_IED_ON); + if (ret != 0) { + ETRACE("failed to turn on display IED"); + } else { + ITRACE("display IED is turned on"); + } +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/common/PrepareListener.h b/merrifield/ips/common/PrepareListener.h new file mode 100644 index 0000000..e048b92 --- /dev/null +++ b/merrifield/ips/common/PrepareListener.h @@ -0,0 +1,35 @@ +/* +// 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. +*/ +#ifndef PREPARE_LISTENER_H +#define PREPARE_LISTENER_H + +#include <IPrepareListener.h> + +namespace android { +namespace intel { + +class PrepareListener : public IPrepareListener { +public: + PrepareListener(); + virtual ~PrepareListener(); +public: + virtual void onProtectedLayerStart(int disp); +}; + +} // namespace intel +} // namespace android + +#endif /* PREPARE_LISTENER_H */ diff --git a/merrifield/ips/common/RotationBufferProvider.cpp b/merrifield/ips/common/RotationBufferProvider.cpp new file mode 100644 index 0000000..65a4db8 --- /dev/null +++ b/merrifield/ips/common/RotationBufferProvider.cpp @@ -0,0 +1,637 @@ +/* +// 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 <common/RotationBufferProvider.h> + +namespace android { +namespace intel { + +#define CHECK_VA_STATUS_RETURN(FUNC) \ +if (vaStatus != VA_STATUS_SUCCESS) {\ + ETRACE(FUNC" failed. vaStatus = %#x", vaStatus);\ + return false;\ +} + +#define CHECK_VA_STATUS_BREAK(FUNC) \ +if (vaStatus != VA_STATUS_SUCCESS) {\ + ETRACE(FUNC" failed. vaStatus = %#x", vaStatus);\ + break;\ +} + +// With this display value, VA will hook VED driver insead of VSP driver for buffer rotation +#define DISPLAYVALUE 0x56454450 + +RotationBufferProvider::RotationBufferProvider(Wsbm* wsbm) + : mWsbm(wsbm), + mVaInitialized(false), + mVaDpy(0), + mVaCfg(0), + mVaCtx(0), + mVaBufFilter(0), + mSourceSurface(0), + mDisplay(DISPLAYVALUE), + mWidth(0), + mHeight(0), + mTransform(0), + mRotatedWidth(0), + mRotatedHeight(0), + mRotatedStride(0), + mTargetIndex(0), + mTTMWrappers(), + mBobDeinterlace(0) +{ + for (int i = 0; i < MAX_SURFACE_NUM; i++) { + mKhandles[i] = 0; + mRotatedSurfaces[i] = 0; + mDrmBuf[i] = NULL; + } +} + +RotationBufferProvider::~RotationBufferProvider() +{ +} + +uint32_t RotationBufferProvider::getMilliseconds() +{ + struct timeval ptimeval; + gettimeofday(&ptimeval, NULL); + return (uint32_t)((ptimeval.tv_sec * 1000) + (ptimeval.tv_usec / 1000)); +} + +bool RotationBufferProvider::initialize() +{ + if (NULL == mWsbm) + return false; + mTTMWrappers.setCapacity(TTM_WRAPPER_COUNT); + return true; +} + +void RotationBufferProvider::deinitialize() +{ + stopVA(); + reset(); +} + +void RotationBufferProvider::reset() +{ + if (mTTMWrappers.size()) { + invalidateCaches(); + } +} + +void RotationBufferProvider::invalidateCaches() +{ + void *buf; + + for (size_t i = 0; i < mTTMWrappers.size(); i++) { + buf = mTTMWrappers.valueAt(i); + if (!mWsbm->destroyTTMBuffer(buf)) + WTRACE("failed to free TTMBuffer"); + } + mTTMWrappers.clear(); +} + +int RotationBufferProvider::transFromHalToVa(int transform) +{ + if (transform == HAL_TRANSFORM_ROT_90) + return VA_ROTATION_90; + if (transform == HAL_TRANSFORM_ROT_180) + return VA_ROTATION_180; + if (transform == HAL_TRANSFORM_ROT_270) + return VA_ROTATION_270; + return 0; +} + +int RotationBufferProvider::getStride(bool isTarget, int width) +{ + int stride = 0; + if (width <= 512) + stride = 512; + else if (width <= 1024) + stride = 1024; + else if (width <= 1280) { + stride = 1280; + if (isTarget) + stride = 2048; + } else if (width <= 2048) + stride = 2048; + else if (width <= 4096) + stride = 4096; + else + stride = (width + 0x3f) & ~0x3f; + return stride; +} + +buffer_handle_t RotationBufferProvider::createWsbmBuffer(int width, int height, void **buf) +{ + int size = width * height * 3 / 2; // YUV420 NV12 format + int allignment = 16 * 2048; // tiling row stride aligned + bool ret = mWsbm->allocateTTMBuffer(size, allignment, buf); + + if (ret == false) { + ETRACE("failed to allocate TTM buffer"); + return 0; + } + + return (buffer_handle_t) mWsbm->getKBufHandle(*buf); +} + +bool RotationBufferProvider::createVaSurface(VideoPayloadBuffer *payload, int transform, bool isTarget) +{ + VAStatus vaStatus; + VASurfaceAttributeTPI attribTpi; + VASurfaceAttributeTPI *vaSurfaceAttrib = &attribTpi; + int stride; + unsigned long buffers; + VASurfaceID *surface; + int width = 0, height = 0, bufferHeight = 0; + + if (isTarget) { + if (transFromHalToVa(transform) == VA_ROTATION_180) { + width = payload->width; + height = payload->height; + } else { + width = payload->height; + height = payload->width; + } + mRotatedWidth = width; + mRotatedHeight = height; + bufferHeight = (height + 0x1f) & ~0x1f; + stride = getStride(isTarget, width); + } else { + width = payload->width; + height = payload->height; + bufferHeight = (payload->height + 0x1f) & ~0x1f; + stride = payload->luma_stride; /* NV12 srouce buffer */ + } + + if (!stride) { + ETRACE("invalid stride value"); + return false; + } + + mBobDeinterlace = payload->bob_deinterlace; + // adjust source target for Bob deinterlace + if (!isTarget && mBobDeinterlace) { + height >>= 1; + bufferHeight >>= 1; + stride <<= 1; + } + + vaSurfaceAttrib->count = 1; + vaSurfaceAttrib->width = width; + vaSurfaceAttrib->height = height; + vaSurfaceAttrib->pixel_format = payload->format; + vaSurfaceAttrib->type = VAExternalMemoryKernelDRMBufffer; + vaSurfaceAttrib->tiling = payload->tiling; + vaSurfaceAttrib->size = (stride * bufferHeight * 3) / 2; + vaSurfaceAttrib->luma_offset = 0; + vaSurfaceAttrib->chroma_v_offset = stride * bufferHeight; + vaSurfaceAttrib->luma_stride = vaSurfaceAttrib->chroma_u_stride + = vaSurfaceAttrib->chroma_v_stride + = stride; + vaSurfaceAttrib->chroma_u_offset = vaSurfaceAttrib->chroma_v_offset; + vaSurfaceAttrib->buffers = &buffers; + + if (isTarget) { + buffer_handle_t khandle = createWsbmBuffer(stride, bufferHeight, &mDrmBuf[mTargetIndex]); + if (khandle == 0) { + ETRACE("failed to create buffer by wsbm"); + return false; + } + + mKhandles[mTargetIndex] = khandle; + vaSurfaceAttrib->buffers[0] = (uintptr_t) khandle; + mRotatedStride = stride; + surface = &mRotatedSurfaces[mTargetIndex]; + } else { + vaSurfaceAttrib->buffers[0] = (uintptr_t) payload->khandle; + surface = &mSourceSurface; + /* set src surface width/height to video crop size */ + if (payload->crop_width && payload->crop_height) { + width = payload->crop_width; + height = (payload->crop_height >> mBobDeinterlace); + } else { + VTRACE("Invalid cropping width or height"); + payload->crop_width = width; + payload->crop_height = height; + } + } + + vaStatus = vaCreateSurfacesWithAttribute(mVaDpy, + width, + height, + VA_RT_FORMAT_YUV420, + 1, + surface, + vaSurfaceAttrib); + if (vaStatus != VA_STATUS_SUCCESS) { + ETRACE("vaCreateSurfacesWithAttribute returns %d", vaStatus); + ETRACE("Attributes: target: %d, width: %d, height %d, bufferHeight %d, tiling %d", + isTarget, width, height, bufferHeight, payload->tiling); + *surface = 0; + return false; + } + + return true; +} + +bool RotationBufferProvider::startVA(VideoPayloadBuffer *payload, int transform) +{ + bool ret = true; + VAStatus vaStatus; + VAEntrypoint *entryPoint; + VAConfigAttrib attribDummy; + int numEntryPoints; + bool supportVideoProcessing = false; + int majorVer = 0, minorVer = 0; + + // VA will hold a copy of the param pointer, so local varialbe doesn't work + mVaDpy = vaGetDisplay(&mDisplay); + if (NULL == mVaDpy) { + ETRACE("failed to get VADisplay"); + return false; + } + + vaStatus = vaInitialize(mVaDpy, &majorVer, &minorVer); + CHECK_VA_STATUS_RETURN("vaInitialize"); + + numEntryPoints = vaMaxNumEntrypoints(mVaDpy); + + if (numEntryPoints <= 0) { + ETRACE("numEntryPoints value is invalid"); + return false; + } + + entryPoint = (VAEntrypoint*)malloc(sizeof(VAEntrypoint) * numEntryPoints); + if (NULL == entryPoint) { + ETRACE("failed to malloc memory for entryPoint"); + return false; + } + + vaStatus = vaQueryConfigEntrypoints(mVaDpy, + VAProfileNone, + entryPoint, + &numEntryPoints); + CHECK_VA_STATUS_RETURN("vaQueryConfigEntrypoints"); + + for (int i = 0; i < numEntryPoints; i++) + if (entryPoint[i] == VAEntrypointVideoProc) + supportVideoProcessing = true; + + free(entryPoint); + entryPoint = NULL; + + if (!supportVideoProcessing) { + ETRACE("VAEntrypointVideoProc is not supported"); + return false; + } + + vaStatus = vaCreateConfig(mVaDpy, + VAProfileNone, + VAEntrypointVideoProc, + &attribDummy, + 0, + &mVaCfg); + CHECK_VA_STATUS_RETURN("vaCreateConfig"); + + // create first target surface + ret = createVaSurface(payload, transform, true); + if (ret == false) { + ETRACE("failed to create target surface with attribute"); + return false; + } + + vaStatus = vaCreateContext(mVaDpy, + mVaCfg, + payload->width, + payload->height, + 0, + &mRotatedSurfaces[0], + 1, + &mVaCtx); + CHECK_VA_STATUS_RETURN("vaCreateContext"); + + VAProcFilterType filters[VAProcFilterCount]; + unsigned int numFilters = VAProcFilterCount; + vaStatus = vaQueryVideoProcFilters(mVaDpy, mVaCtx, filters, &numFilters); + CHECK_VA_STATUS_RETURN("vaQueryVideoProcFilters"); + + bool supportVideoProcFilter = false; + for (unsigned int j = 0; j < numFilters; j++) + if (filters[j] == VAProcFilterNone) + supportVideoProcFilter = true; + + if (!supportVideoProcFilter) { + ETRACE("VAProcFilterNone is not supported"); + return false; + } + + VAProcFilterParameterBuffer filter; + filter.type = VAProcFilterNone; + filter.value = 0; + + vaStatus = vaCreateBuffer(mVaDpy, + mVaCtx, + VAProcFilterParameterBufferType, + sizeof(filter), + 1, + &filter, + &mVaBufFilter); + CHECK_VA_STATUS_RETURN("vaCreateBuffer"); + + VAProcPipelineCaps pipelineCaps; + unsigned int numCaps = 1; + vaStatus = vaQueryVideoProcPipelineCaps(mVaDpy, + mVaCtx, + &mVaBufFilter, + numCaps, + &pipelineCaps); + CHECK_VA_STATUS_RETURN("vaQueryVideoProcPipelineCaps"); + + if (!(pipelineCaps.rotation_flags & (1 << transFromHalToVa(transform)))) { + ETRACE("VA_ROTATION_xxx: 0x%08x is not supported by the filter", + transFromHalToVa(transform)); + return false; + } + + mVaInitialized = true; + + return true; +} + +bool RotationBufferProvider::setupRotationBuffer(VideoPayloadBuffer *payload, int transform) +{ +#ifdef DEBUG_ROTATION_PERFROMANCE + uint32_t setup_Begin = getMilliseconds(); +#endif + VAStatus vaStatus; + int stride; + bool ret = false; + + if (payload->format != VA_FOURCC_NV12 || payload->width == 0 || payload->height == 0) { + WTRACE("payload data is not correct: format %#x, width %d, height %d", + payload->format, payload->width, payload->height); + return ret; + } + + if (payload->width > 1280 && payload->width <= 2048) { + payload->tiling = 1; + } + + do { + if (isContextChanged(payload->width, payload->height, transform)) { + DTRACE("VA is restarted as rotation context changes"); + + if (mVaInitialized) { + stopVA(); // need to re-initialize VA for new rotation config + } + mTransform = transform; + mWidth = payload->width; + mHeight = payload->height; + } + + if (!mVaInitialized) { + ret = startVA(payload, transform); + if (ret == false) { + vaStatus = VA_STATUS_ERROR_OPERATION_FAILED; + break; + } + } + + // start to create next target surface + if (!mRotatedSurfaces[mTargetIndex]) { + ret = createVaSurface(payload, transform, true); + if (ret == false) { + ETRACE("failed to create target surface with attribute"); + vaStatus = VA_STATUS_ERROR_OPERATION_FAILED; + break; + } + } + + // create source surface + ret = createVaSurface(payload, transform, false); + if (ret == false) { + ETRACE("failed to create source surface with attribute"); + vaStatus = VA_STATUS_ERROR_OPERATION_FAILED; + break; + } + +#ifdef DEBUG_ROTATION_PERFROMANCE + uint32_t beginPicture = getMilliseconds(); +#endif + vaStatus = vaBeginPicture(mVaDpy, mVaCtx, mRotatedSurfaces[mTargetIndex]); + CHECK_VA_STATUS_BREAK("vaBeginPicture"); + + VABufferID pipelineBuf; + void *p; + VAProcPipelineParameterBuffer *pipelineParam; + vaStatus = vaCreateBuffer(mVaDpy, + mVaCtx, + VAProcPipelineParameterBufferType, + sizeof(*pipelineParam), + 1, + NULL, + &pipelineBuf); + CHECK_VA_STATUS_BREAK("vaCreateBuffer"); + + vaStatus = vaMapBuffer(mVaDpy, pipelineBuf, &p); + CHECK_VA_STATUS_BREAK("vaMapBuffer"); + + pipelineParam = (VAProcPipelineParameterBuffer*)p; + pipelineParam->surface = mSourceSurface; + pipelineParam->rotation_state = transFromHalToVa(transform); + pipelineParam->filters = &mVaBufFilter; + pipelineParam->num_filters = 1; + pipelineParam->surface_region = NULL; + pipelineParam->output_region = NULL; + pipelineParam->num_forward_references = 0; + pipelineParam->num_backward_references = 0; + vaStatus = vaUnmapBuffer(mVaDpy, pipelineBuf); + CHECK_VA_STATUS_BREAK("vaUnmapBuffer"); + + vaStatus = vaRenderPicture(mVaDpy, mVaCtx, &pipelineBuf, 1); + CHECK_VA_STATUS_BREAK("vaRenderPicture"); + + vaStatus = vaEndPicture(mVaDpy, mVaCtx); + CHECK_VA_STATUS_BREAK("vaEndPicture"); + + vaStatus = vaSyncSurface(mVaDpy, mRotatedSurfaces[mTargetIndex]); + CHECK_VA_STATUS_BREAK("vaSyncSurface"); + +#ifdef DEBUG_ROTATION_PERFROMANCE + ITRACE("time spent %dms from vaBeginPicture to vaSyncSurface", + getMilliseconds() - beginPicture); +#endif + + // Populate payload fields so that overlayPlane can flip the buffer + payload->rotated_width = mRotatedStride; + payload->rotated_height = mRotatedHeight; + payload->rotated_buffer_handle = mKhandles[mTargetIndex]; + // setting client transform to 0 to force re-generating rotated buffer whenever needed. + payload->client_transform = 0; + mTargetIndex++; + if (mTargetIndex >= MAX_SURFACE_NUM) + mTargetIndex = 0; + + } while (0); + +#ifdef DEBUG_ROTATION_PERFROMANCE + ITRACE("time spent %dms for setupRotationBuffer", + getMilliseconds() - setup_Begin); +#endif + + if (mSourceSurface > 0) { + vaStatus = vaDestroySurfaces(mVaDpy, &mSourceSurface, 1); + if (vaStatus != VA_STATUS_SUCCESS) + WTRACE("vaDestroySurfaces failed, vaStatus = %d", vaStatus); + mSourceSurface = 0; + } + + if (vaStatus != VA_STATUS_SUCCESS) { + stopVA(); + return false; // To not block HWC, just abort instead of retry + } + + if (!payload->khandle) { + WTRACE("khandle is reset by decoder, surface is invalid!"); + return false; + } + + return true; +} + +bool RotationBufferProvider::prepareBufferInfo(int w, int h, int stride, VideoPayloadBuffer *payload, void *user_pt) +{ + int chroma_offset, size; + void *buf = NULL; + + payload->width = payload->crop_width = w; + payload->height = payload->crop_height = h; + payload->coded_width = ((w + 0xf) & ~0xf); + payload->coded_height = ((h + 0xf) & ~0xf); + payload->format = VA_FOURCC_NV12; + payload->tiling = 1; + payload->luma_stride = stride; + payload->chroma_u_stride = stride; + payload->chroma_v_stride = stride; + payload->client_transform = 0; + payload->bob_deinterlace = 0; + + chroma_offset = stride * h; + size = stride * h + stride * h / 2; + + ssize_t index; + index = mTTMWrappers.indexOfKey((uint64_t)user_pt); + if (index < 0) { + VTRACE("wrapped userPt as wsbm buffer"); + bool ret = mWsbm->allocateTTMBufferUB(size, 0, &buf, user_pt); + if (ret == false) { + ETRACE("failed to allocate TTM buffer"); + return ret; + } + + if (mTTMWrappers.size() >= TTM_WRAPPER_COUNT) { + WTRACE("mTTMWrappers is unexpectedly full. Invalidate caches"); + invalidateCaches(); + } + + index = mTTMWrappers.add((uint64_t)user_pt, buf); + } else { + VTRACE("got wsbmBuffer in saved caches"); + buf = mTTMWrappers.valueAt(index); + } + + payload->khandle = (buffer_handle_t) mWsbm->getKBufHandle(buf); + return true; +} + +void RotationBufferProvider::freeVaSurfaces() +{ + bool ret; + VAStatus vaStatus; + + for (int i = 0; i < MAX_SURFACE_NUM; i++) { + if (NULL != mDrmBuf[i]) { + ret = mWsbm->destroyTTMBuffer(mDrmBuf[i]); + if (!ret) + WTRACE("failed to free TTMBuffer"); + mDrmBuf[i] = NULL; + } + } + + // remove wsbm buffer ref from VA + for (int j = 0; j < MAX_SURFACE_NUM; j++) { + if (0 != mRotatedSurfaces[j]) { + vaStatus = vaDestroySurfaces(mVaDpy, &mRotatedSurfaces[j], 1); + if (vaStatus != VA_STATUS_SUCCESS) + WTRACE("vaDestroySurfaces failed, vaStatus = %d", vaStatus); + } + mRotatedSurfaces[j] = 0; + } +} + +void RotationBufferProvider::stopVA() +{ + freeVaSurfaces(); + + if (0 != mVaBufFilter) + vaDestroyBuffer(mVaDpy, mVaBufFilter); + if (0 != mVaCfg) + vaDestroyConfig(mVaDpy,mVaCfg); + if (0 != mVaCtx) + vaDestroyContext(mVaDpy, mVaCtx); + if (0 != mVaDpy) + vaTerminate(mVaDpy); + + mVaInitialized = false; + + for (int i = 0; i < MAX_SURFACE_NUM; i++) { + mKhandles[i] = 0; + mRotatedSurfaces[i] = 0; + mDrmBuf[i] = NULL; + } + // reset VA variable + mVaDpy = 0; + mVaCfg = 0; + mVaCtx = 0; + mVaBufFilter = 0; + mSourceSurface = 0; + + mWidth = 0; + mHeight = 0; + mRotatedWidth = 0; + mRotatedHeight = 0; + mRotatedStride = 0; + mTargetIndex = 0; + mBobDeinterlace = 0; +} + +bool RotationBufferProvider::isContextChanged(int width, int height, int transform) +{ + // check rotation config + if (height == mHeight && + width == mWidth && + transform == mTransform) { + return false; + } + + return true; +} + +} // name space intel +} // name space android diff --git a/merrifield/ips/common/RotationBufferProvider.h b/merrifield/ips/common/RotationBufferProvider.h new file mode 100644 index 0000000..edf4fa7 --- /dev/null +++ b/merrifield/ips/common/RotationBufferProvider.h @@ -0,0 +1,102 @@ +/* +// 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. +*/ + +#ifndef __ROTATIONO_BUFFER_PROVIDER_H__ +#define __ROTATIONO_BUFFER_PROVIDER_H__ + +#include <va/va.h> +#include <sys/time.h> +#include <va/va_tpi.h> +#include <va/va_vpp.h> +#include <common/Wsbm.h> +#include <utils/Timers.h> +#include <utils/KeyedVector.h> +#include <va/va_android.h> +#include <common/VideoPayloadBuffer.h> + +namespace android { +namespace intel { + +#define Display unsigned int +typedef void* VADisplay; +typedef int VAStatus; + +class RotationBufferProvider { + +public: + RotationBufferProvider(Wsbm* wsbm); + ~RotationBufferProvider(); + + bool initialize(); + void deinitialize(); + void reset(); + bool setupRotationBuffer(VideoPayloadBuffer *payload, int transform); + bool prepareBufferInfo(int, int, int, VideoPayloadBuffer *, void *); + +private: + void invalidateCaches(); + bool startVA(VideoPayloadBuffer *payload, int transform); + void stopVA(); + bool isContextChanged(int width, int height, int transform); + int transFromHalToVa(int transform); + buffer_handle_t createWsbmBuffer(int width, int height, void **buf); + int getStride(bool isTarget, int width); + bool createVaSurface(VideoPayloadBuffer *payload, int transform, bool isTarget); + void freeVaSurfaces(); + inline uint32_t getMilliseconds(); + +private: + enum { + MAX_SURFACE_NUM = 4 + }; + + Wsbm* mWsbm; + + bool mVaInitialized; + VADisplay mVaDpy; + VAConfigID mVaCfg; + VAContextID mVaCtx; + VABufferID mVaBufFilter; + VASurfaceID mSourceSurface; + Display mDisplay; + + // rotation config variables + int mWidth; + int mHeight; + int mTransform; + + int mRotatedWidth; + int mRotatedHeight; + int mRotatedStride; + + int mTargetIndex; + buffer_handle_t mKhandles[MAX_SURFACE_NUM]; + VASurfaceID mRotatedSurfaces[MAX_SURFACE_NUM]; + void *mDrmBuf[MAX_SURFACE_NUM]; + + enum { + TTM_WRAPPER_COUNT = 10, + }; + + KeyedVector<uint64_t, void*> mTTMWrappers; /* userPt/wsbmBuffer */ + + int mBobDeinterlace; +}; + +} // name space intel +} // name space android + +#endif diff --git a/merrifield/ips/common/SpritePlaneBase.cpp b/merrifield/ips/common/SpritePlaneBase.cpp new file mode 100644 index 0000000..890aec8 --- /dev/null +++ b/merrifield/ips/common/SpritePlaneBase.cpp @@ -0,0 +1,53 @@ +/* +// 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 <common/SpritePlaneBase.h> +#include <common/PixelFormat.h> + +namespace android { +namespace intel { + +SpritePlaneBase::SpritePlaneBase(int index, int disp) + : DisplayPlane(index, PLANE_SPRITE, disp), + mForceBottom(false), + mAbovePrimary(true) +{ + CTRACE(); +} + +SpritePlaneBase::~SpritePlaneBase() +{ + CTRACE(); +} + +bool SpritePlaneBase::flip(void *ctx) +{ + CTRACE(); + return DisplayPlane::flip(ctx); +} + +bool SpritePlaneBase::enable() +{ + return enablePlane(true); +} + +bool SpritePlaneBase::disable() +{ + return enablePlane(false); +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/common/SpritePlaneBase.h b/merrifield/ips/common/SpritePlaneBase.h new file mode 100644 index 0000000..78bbd6e --- /dev/null +++ b/merrifield/ips/common/SpritePlaneBase.h @@ -0,0 +1,52 @@ +/* +// 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. +*/ +#ifndef SPRITE_PLANE_BASE_H +#define SPRITE_PLANE_BASE_H + +#include <utils/KeyedVector.h> +#include <hal_public.h> +#include <BufferCache.h> +#include <DisplayPlane.h> + +namespace android { +namespace intel { + +class SpritePlaneBase : public DisplayPlane { +public: + SpritePlaneBase(int index, int disp); + virtual ~SpritePlaneBase(); +public: + // hardware operations + virtual bool flip(void *ctx); + virtual bool enable(); + virtual bool disable(); + virtual bool isDisabled() = 0; + + // display device + virtual void* getContext() const = 0; +protected: + virtual bool setDataBuffer(BufferMapper& mapper) = 0; + virtual bool enablePlane(bool enabled) = 0; +protected: + bool mForceBottom; + bool mAbovePrimary; +}; + +} // namespace intel +} // namespace android + +#endif /* SPRITE_PLANE_BASE_H */ + diff --git a/merrifield/ips/common/TTMBufferMapper.cpp b/merrifield/ips/common/TTMBufferMapper.cpp new file mode 100644 index 0000000..7c3ed0d --- /dev/null +++ b/merrifield/ips/common/TTMBufferMapper.cpp @@ -0,0 +1,103 @@ +/* +// 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 <common/TTMBufferMapper.h> + +namespace android { +namespace intel { + +TTMBufferMapper::TTMBufferMapper(Wsbm& wsbm, DataBuffer& buffer) + : BufferMapper(buffer), + mRefCount(0), + mWsbm(wsbm), + mBufferObject(0), + mGttOffsetInPage(0), + mCpuAddress(0), + mSize(0) +{ + CTRACE(); +} + +TTMBufferMapper::~TTMBufferMapper() +{ + CTRACE(); +} + +bool TTMBufferMapper::map() +{ + void *wsbmBufferObject = 0; + buffer_handle_t handle; + void *virtAddr; + uint32_t gttOffsetInPage; + + CTRACE(); + + handle = getHandle(); + + bool ret = mWsbm.wrapTTMBuffer((int64_t)handle, &wsbmBufferObject); + if (ret == false) { + ETRACE("failed to map TTM buffer"); + return false; + } + + // TODO: review this later + ret = mWsbm.waitIdleTTMBuffer(wsbmBufferObject); + if (ret == false) { + ETRACE("failed to wait ttm buffer idle"); + return false; + } + + virtAddr = mWsbm.getCPUAddress(wsbmBufferObject); + gttOffsetInPage = mWsbm.getGttOffset(wsbmBufferObject); + + if (!gttOffsetInPage || !virtAddr) { + WTRACE("offset = %#x, addr = %p.", gttOffsetInPage, virtAddr); + return false; + } + + // update parameters + mBufferObject = wsbmBufferObject; + mGttOffsetInPage = gttOffsetInPage; + mCpuAddress = virtAddr; + mSize = 0; + return true; +} + +bool TTMBufferMapper::unmap() +{ + CTRACE(); + + if (!mBufferObject) + return false; + + mWsbm.unreferenceTTMBuffer(mBufferObject); + + mGttOffsetInPage = 0; + mCpuAddress = 0; + mSize = 0; + mBufferObject = 0; + return true; +} + +bool TTMBufferMapper::waitIdle() +{ + return mWsbm.waitIdleTTMBuffer(mBufferObject); +} + +} // namespace intel +} // namespace android + + diff --git a/merrifield/ips/common/TTMBufferMapper.h b/merrifield/ips/common/TTMBufferMapper.h new file mode 100644 index 0000000..46ed26e --- /dev/null +++ b/merrifield/ips/common/TTMBufferMapper.h @@ -0,0 +1,70 @@ +/* +// 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. +*/ +#ifndef TTMBUFFERMAPPER_H_ +#define TTMBUFFERMAPPER_H_ + +#include <DataBuffer.h> +#include <BufferMapper.h> +#include <common/Wsbm.h> + +namespace android { +namespace intel { + +class TTMBufferMapper : public BufferMapper { +public: + TTMBufferMapper(Wsbm& wsbm, DataBuffer& buffer); + virtual ~TTMBufferMapper(); +public: + bool map(); + bool unmap(); + + uint32_t getGttOffsetInPage(int subIndex) const { + return mGttOffsetInPage; + } + void* getCpuAddress(int subIndex) const { + return mCpuAddress; + } + uint32_t getSize(int subIndex) const { + return mSize; + } + buffer_handle_t getKHandle(int subIndex) { + return 0; + } + buffer_handle_t getFbHandle(int subIndex) { + return 0; + } + void putFbHandle() { + return; + } + + // wait idle + bool waitIdle(); +private: + int mRefCount; + Wsbm& mWsbm; + void* mBufferObject; + + // mapped info + uint32_t mGttOffsetInPage; + void* mCpuAddress; + uint32_t mSize; +}; + +} //namespace intel +} //namespace android + + +#endif /* TTMBUFFERMAPPER_H_ */ diff --git a/merrifield/ips/common/VideoPayloadBuffer.h b/merrifield/ips/common/VideoPayloadBuffer.h new file mode 100644 index 0000000..1faf84a --- /dev/null +++ b/merrifield/ips/common/VideoPayloadBuffer.h @@ -0,0 +1,87 @@ +/* +// 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. +*/ +#ifndef VIDEO_PAYLOAD_BUFFER_H +#define VIDEO_PAYLOAD_BUFFER_H + +#include <utils/Timers.h> +namespace android { +namespace intel { + +struct VideoPayloadBuffer { + // transform made by clients (clients to hwc) + int client_transform; + int metadata_transform; + int rotated_width; + int rotated_height; + int surface_protected; + int force_output_method; + buffer_handle_t rotated_buffer_handle; + uint32_t renderStatus; + unsigned int used_by_widi; + int bob_deinterlace; + int tiling; + uint32_t width; + uint32_t height; + uint32_t luma_stride; + uint32_t chroma_u_stride; + uint32_t chroma_v_stride; + uint32_t format; + buffer_handle_t khandle; + int64_t timestamp; + + uint32_t rotate_luma_stride; + uint32_t rotate_chroma_u_stride; + uint32_t rotate_chroma_v_stride; + + nsecs_t hwc_timestamp; + uint32_t layer_transform; + + void *native_window; + buffer_handle_t scaling_khandle; + uint32_t scaling_width; + uint32_t scaling_height; + + uint32_t scaling_luma_stride; + uint32_t scaling_chroma_u_stride; + uint32_t scaling_chroma_v_stride; + + uint32_t crop_width; + uint32_t crop_height; + + uint32_t coded_width; + uint32_t coded_height; + uint32_t csc_mode; + uint32_t video_range; + uint32_t initialized; +}; + + +// force output method values +enum { + FORCE_OUTPUT_INVALID = 0, + FORCE_OUTPUT_GPU, + FORCE_OUTPUT_OVERLAY, + FORCE_OUTPUT_SW_DECODE, +}; + + +} // namespace intel +} // namespace android + + +#endif // VIDEO_PAYLOAD_BUFFER_H + + diff --git a/merrifield/ips/common/VideoPayloadManager.cpp b/merrifield/ips/common/VideoPayloadManager.cpp new file mode 100644 index 0000000..33e2afb --- /dev/null +++ b/merrifield/ips/common/VideoPayloadManager.cpp @@ -0,0 +1,123 @@ +/* +// 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 <BufferMapper.h> +#include <common/GrallocSubBuffer.h> +#include <common/VideoPayloadManager.h> +#include <common/VideoPayloadBuffer.h> + +namespace android { +namespace intel { + +VideoPayloadManager::VideoPayloadManager() + : IVideoPayloadManager() +{ +} + +VideoPayloadManager::~VideoPayloadManager() +{ +} + +bool VideoPayloadManager::getMetaData(BufferMapper *mapper, MetaData *metadata) +{ + if (!mapper || !metadata) { + ETRACE("Null input params"); + return false; + } + + VideoPayloadBuffer *p = (VideoPayloadBuffer*) mapper->getCpuAddress(SUB_BUFFER1); + if (!p) { + ETRACE("Got null payload from display buffer"); + return false; + } + + metadata->format = p->format; + metadata->transform = p->metadata_transform; + metadata->timestamp = p->timestamp; + + metadata->normalBuffer.khandle = p->khandle; + metadata->normalBuffer.width = p->crop_width; + metadata->normalBuffer.height = p->crop_height; + metadata->normalBuffer.bufWidth = p->width; + metadata->normalBuffer.bufHeight = p->height; + metadata->normalBuffer.lumaStride = p->luma_stride; + metadata->normalBuffer.chromaUStride = p->chroma_u_stride; + metadata->normalBuffer.chromaVStride = p->chroma_v_stride; + metadata->normalBuffer.offsetX = 0; + metadata->normalBuffer.offsetY = 0; + metadata->normalBuffer.tiled = (p->width > 1280); + + metadata->scalingBuffer.khandle = p->scaling_khandle; + metadata->scalingBuffer.width = p->scaling_width; + metadata->scalingBuffer.height = p->scaling_height; + metadata->scalingBuffer.bufWidth = align_to(p->scaling_width, 32); + metadata->scalingBuffer.bufHeight = align_to(p->scaling_height, 32); + metadata->scalingBuffer.lumaStride = p->scaling_luma_stride; + metadata->scalingBuffer.chromaUStride = p->scaling_chroma_u_stride; + metadata->scalingBuffer.chromaVStride = p->scaling_chroma_v_stride; + metadata->scalingBuffer.offsetX = 0; + metadata->scalingBuffer.offsetY = 0; + metadata->scalingBuffer.tiled = false; + + metadata->rotationBuffer.khandle = p->rotated_buffer_handle; + uint16_t rotSrcWidth; + uint16_t rotSrcHeight; + if (metadata->scalingBuffer.khandle) { + rotSrcWidth = metadata->scalingBuffer.width; + rotSrcHeight = metadata->scalingBuffer.height; + } else { + rotSrcWidth = metadata->normalBuffer.width; + rotSrcHeight = metadata->normalBuffer.height; + } + if (metadata->transform == 0 || metadata->transform == HAL_TRANSFORM_ROT_180) { + metadata->rotationBuffer.width = rotSrcWidth; + metadata->rotationBuffer.height = rotSrcHeight; + } else { + metadata->rotationBuffer.width = rotSrcHeight; + metadata->rotationBuffer.height = rotSrcWidth; + } + metadata->rotationBuffer.bufWidth = p->rotated_width; + metadata->rotationBuffer.bufHeight = p->rotated_height; + metadata->rotationBuffer.lumaStride = p->rotate_luma_stride; + metadata->rotationBuffer.chromaUStride = p->rotate_chroma_u_stride; + metadata->rotationBuffer.chromaVStride = p->rotate_chroma_v_stride; + metadata->rotationBuffer.offsetX = (-metadata->rotationBuffer.width) & 0xf; + metadata->rotationBuffer.offsetY = (-metadata->rotationBuffer.height) & 0xf; + metadata->rotationBuffer.tiled = metadata->normalBuffer.tiled; + + return true; +} + +bool VideoPayloadManager::setRenderStatus(BufferMapper *mapper, bool renderStatus) +{ + if (!mapper) { + ETRACE("Null mapper param"); + return false; + } + + VideoPayloadBuffer* p = (VideoPayloadBuffer*) mapper->getCpuAddress(SUB_BUFFER1); + if (!p) { + ETRACE("Got null payload from display buffer"); + return false; + } + + p->renderStatus = renderStatus ? 1 : 0; + return true; +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/common/VideoPayloadManager.h b/merrifield/ips/common/VideoPayloadManager.h new file mode 100644 index 0000000..563003d --- /dev/null +++ b/merrifield/ips/common/VideoPayloadManager.h @@ -0,0 +1,42 @@ +/* +// 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. +*/ +#ifndef VIDEO_PAYLOAD_MANAGER_H +#define VIDEO_PAYLOAD_MANAGER_H + +#include <IVideoPayloadManager.h> + +namespace android { +namespace intel { + +class BufferMapper; + +class VideoPayloadManager : public IVideoPayloadManager { + +public: + VideoPayloadManager(); + virtual ~VideoPayloadManager(); + + // IVideoPayloadManager +public: + virtual bool getMetaData(BufferMapper *mapper, MetaData *metadata); + virtual bool setRenderStatus(BufferMapper *mapper, bool renderStatus); + +}; // class VideoPayloadManager + +} // namespace intel +} // namespace android + +#endif /* VIDEO_PAYLOAD_MANAGER_H */ diff --git a/merrifield/ips/common/VsyncControl.cpp b/merrifield/ips/common/VsyncControl.cpp new file mode 100644 index 0000000..9e576fd --- /dev/null +++ b/merrifield/ips/common/VsyncControl.cpp @@ -0,0 +1,84 @@ +/* +// 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 <Drm.h> +#include <Hwcomposer.h> +#include <common/VsyncControl.h> + +namespace android { +namespace intel { + +VsyncControl::VsyncControl() + : IVsyncControl(), + mInitialized(false) +{ +} + +VsyncControl::~VsyncControl() +{ + WARN_IF_NOT_DEINIT(); +} + +bool VsyncControl::initialize() +{ + mInitialized = true; + return true; +} + +void VsyncControl::deinitialize() +{ + mInitialized = false; +} + +bool VsyncControl::control(int disp, bool enabled) +{ + ATRACE("disp = %d, enabled = %d", disp, enabled); + + struct drm_psb_vsync_set_arg arg; + memset(&arg, 0, sizeof(struct drm_psb_vsync_set_arg)); + + // pipe equals to disp + arg.vsync.pipe = disp; + + if (enabled) { + arg.vsync_operation_mask = VSYNC_ENABLE; + } else { + arg.vsync_operation_mask = VSYNC_DISABLE; + } + Drm *drm = Hwcomposer::getInstance().getDrm(); + return drm->writeReadIoctl(DRM_PSB_VSYNC_SET, &arg, sizeof(arg)); +} + +bool VsyncControl::wait(int disp, int64_t& timestamp) +{ + ATRACE("disp = %d", disp); + + struct drm_psb_vsync_set_arg arg; + memset(&arg, 0, sizeof(struct drm_psb_vsync_set_arg)); + + arg.vsync_operation_mask = VSYNC_WAIT; + + // pipe equals to disp + arg.vsync.pipe = disp; + + Drm *drm = Hwcomposer::getInstance().getDrm(); + bool ret = drm->writeReadIoctl(DRM_PSB_VSYNC_SET, &arg, sizeof(arg)); + timestamp = (int64_t)arg.vsync.timestamp; + return ret; +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/common/VsyncControl.h b/merrifield/ips/common/VsyncControl.h new file mode 100644 index 0000000..d5ffa11 --- /dev/null +++ b/merrifield/ips/common/VsyncControl.h @@ -0,0 +1,43 @@ +/* +// 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. +*/ +#ifndef VSYNC_CONTROL_H +#define VSYNC_CONTROL_H + +#include <IVsyncControl.h> + +namespace android { +namespace intel { + +class VsyncControl : public IVsyncControl { +public: + VsyncControl(); + virtual ~VsyncControl(); + +public: + bool initialize(); + void deinitialize(); + bool control(int disp, bool enabled); + bool wait(int disp, int64_t& timestamp); + +private: + bool mInitialized; +}; + +} // namespace intel +} // namespace android + + +#endif /* VSYNC_CONTROL_H */ diff --git a/merrifield/ips/common/Wsbm.cpp b/merrifield/ips/common/Wsbm.cpp new file mode 100644 index 0000000..ab92b1b --- /dev/null +++ b/merrifield/ips/common/Wsbm.cpp @@ -0,0 +1,136 @@ +/* +// 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 <common/Wsbm.h> + +Wsbm::Wsbm(int drmFD) + : mInitialized(false) +{ + CTRACE(); + mDrmFD = drmFD; +} + +Wsbm::~Wsbm() +{ + WARN_IF_NOT_DEINIT(); +} + +bool Wsbm::initialize() +{ + if (mInitialized) { + WTRACE("object is initialized"); + return true; + } + + int ret = psbWsbmInitialize(mDrmFD); + if (ret) { + ETRACE("failed to initialize Wsbm"); + return false; + } + + mInitialized = true; + return true; +} + +void Wsbm::deinitialize() +{ + if (!mInitialized) { + return; + } + psbWsbmTakedown(); + mInitialized = false; +} + +bool Wsbm::allocateTTMBuffer(uint32_t size, uint32_t align, void ** buf) +{ + int ret = psbWsbmAllocateTTMBuffer(size, align, buf); + if (ret) { + ETRACE("failed to allocate buffer"); + return false; + } + + return true; +} + +bool Wsbm::allocateTTMBufferUB(uint32_t size, uint32_t align, void ** buf, void *user_pt) +{ + int ret = psbWsbmAllocateFromUB(size, align, buf, user_pt); + if (ret) { + ETRACE("failed to allocate UB buffer"); + return false; + } + + return true; +} + +bool Wsbm::destroyTTMBuffer(void * buf) +{ + int ret = psbWsbmDestroyTTMBuffer(buf); + if (ret) { + ETRACE("failed to destroy buffer"); + return false; + } + + return true; +} + +void * Wsbm::getCPUAddress(void * buf) +{ + return psbWsbmGetCPUAddress(buf); +} + +uint32_t Wsbm::getGttOffset(void * buf) +{ + return psbWsbmGetGttOffset(buf); +} + +bool Wsbm::wrapTTMBuffer(int64_t handle, void **buf) +{ + int ret = psbWsbmWrapTTMBuffer(handle, buf); + if (ret) { + ETRACE("failed to wrap buffer"); + return false; + } + + return true; +} + +bool Wsbm::unreferenceTTMBuffer(void *buf) +{ + int ret = psbWsbmUnReference(buf); + if (ret) { + ETRACE("failed to unreference buffer"); + return false; + } + + return true; +} + +uint64_t Wsbm::getKBufHandle(void *buf) +{ + return psbWsbmGetKBufHandle(buf); +} + +bool Wsbm::waitIdleTTMBuffer(void *buf) +{ + int ret = psbWsbmWaitIdle(buf); + if (ret) { + ETRACE("failed to wait ttm buffer for idle"); + return false; + } + + return true; +} diff --git a/merrifield/ips/common/Wsbm.h b/merrifield/ips/common/Wsbm.h new file mode 100644 index 0000000..9e2b357 --- /dev/null +++ b/merrifield/ips/common/Wsbm.h @@ -0,0 +1,47 @@ +/* +// 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. +*/ +#ifndef WSBM_H__ +#define WSBM_H__ + +#include <common/WsbmWrapper.h> + +/** + * Class: WSBM + * A wrapper class to use libwsbm functionalities + */ +class Wsbm +{ +private: + int mDrmFD; +public: + Wsbm(int drmFD); + ~Wsbm(); + bool initialize(); + void deinitialize(); + bool allocateTTMBuffer(uint32_t size, uint32_t align,void ** buf); + bool allocateTTMBufferUB(uint32_t size, uint32_t align, void ** buf, void *user_pt); + bool destroyTTMBuffer(void * buf); + void * getCPUAddress(void * buf); + uint32_t getGttOffset(void * buf); + bool wrapTTMBuffer(int64_t handle, void **buf); + bool unreferenceTTMBuffer(void *buf); + bool waitIdleTTMBuffer(void *buf); + uint64_t getKBufHandle(void *buf); +private: + bool mInitialized; +}; + +#endif /*__INTEL_WSBM_H__*/ diff --git a/merrifield/ips/common/WsbmWrapper.c b/merrifield/ips/common/WsbmWrapper.c new file mode 100644 index 0000000..5e4161e --- /dev/null +++ b/merrifield/ips/common/WsbmWrapper.c @@ -0,0 +1,401 @@ +/* +// 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 <wsbm_pool.h> +#include <wsbm_driver.h> +#include <wsbm_manager.h> +#include <wsbm_util.h> +#include <drm/ttm/ttm_placement.h> +#include <linux/psb_drm.h> +#include <xf86drm.h> +#include <HwcTrace.h> + +struct _WsbmBufferPool * mainPool = NULL; + +struct PsbWsbmValidateNode +{ + struct _ValidateNode base; + struct psb_validate_arg arg; +}; + +static inline uint32_t align_to(uint32_t arg, uint32_t align) +{ + return ((arg + (align - 1)) & (~(align - 1))); +} + +static struct _ValidateNode * pvrAlloc(struct _WsbmVNodeFuncs * func, + int typeId) +{ + CTRACE(); + if(typeId == 0) { + struct PsbWsbmValidateNode * vNode = malloc(sizeof(*vNode)); + if(!vNode) { + ETRACE("failed to allocate memory"); + return NULL; + } + + vNode->base.func = func; + vNode->base.type_id = 0; + return &vNode->base; + } else { + struct _ValidateNode * node = malloc(sizeof(*node)); + if(!node) { + ETRACE("failed to allocate node"); + return NULL; + } + + node->func = func; + node->type_id = 1; + return node; + } +} + +static void pvrFree(struct _ValidateNode * node) +{ + CTRACE(); + if(node->type_id == 0) { + free(containerOf(node, struct PsbWsbmValidateNode, base)); + } else { + free(node); + } +} + +static void pvrClear(struct _ValidateNode * node) +{ + CTRACE(); + if(node->type_id == 0) { + struct PsbWsbmValidateNode * vNode = + containerOf(node, struct PsbWsbmValidateNode, base); + memset(&vNode->arg.d.req, 0, sizeof(vNode->arg.d.req)); + } +} + +static struct _WsbmVNodeFuncs vNodeFuncs = { + .alloc = pvrAlloc, + .free = pvrFree, + .clear = pvrClear, +}; + +void psbWsbmTakedown() +{ + CTRACE(); + + if (mainPool) { + wsbmPoolTakeDown(mainPool); + mainPool = NULL; + } + + if (wsbmIsInitialized()) { + wsbmTakedown(); + } +} + +int psbWsbmInitialize(int drmFD) +{ + union drm_psb_extension_arg arg; + const char drmExt[] = "psb_ttm_placement_alphadrop"; + int ret = 0; + + CTRACE(); + + if (drmFD <= 0) { + ETRACE("invalid drm fd %d", drmFD); + return drmFD; + } + + /*init wsbm*/ + ret = wsbmInit(wsbmNullThreadFuncs(), &vNodeFuncs); + if (ret) { + ETRACE("failed to initialize Wsbm, error code %d", ret); + return ret; + } + + VTRACE("DRM_PSB_EXTENSION %d", DRM_PSB_EXTENSION); + + /*get devOffset via drm IOCTL*/ + strncpy(arg.extension, drmExt, sizeof(drmExt)); + + ret = drmCommandWriteRead(drmFD, 6/*DRM_PSB_EXTENSION*/, &arg, sizeof(arg)); + if(ret || !arg.rep.exists) { + ETRACE("failed to get device offset, error code %d", ret); + goto out; + } + + VTRACE("ioctl offset %#x", arg.rep.driver_ioctl_offset); + + mainPool = wsbmTTMPoolInit(drmFD, arg.rep.driver_ioctl_offset); + if(!mainPool) { + ETRACE("failed to initialize TTM Pool"); + ret = -EINVAL; + goto out; + } + + VTRACE("Wsbm initialization succeeded. mainPool %p", mainPool); + + return 0; + +out: + psbWsbmTakedown(); + return ret; +} + +int psbWsbmAllocateFromUB(uint32_t size, uint32_t align, void ** buf, void *user_pt) +{ + struct _WsbmBufferObject * wsbmBuf = NULL; + int ret = 0; + int offset = 0; + + ATRACE("size %d", align_to(size, 4096)); + + if(!buf || !user_pt) { + ETRACE("invalid parameter"); + return -EINVAL; + } + + VTRACE("mainPool %p", mainPool); + + ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, align, + DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_CACHED | + WSBM_PL_FLAG_NO_EVICT | WSBM_PL_FLAG_SHARED); + if(ret) { + ETRACE("wsbmGenBuffers failed with error code %d", ret); + return ret; + } + + ret = wsbmBODataUB(wsbmBuf, + align_to(size, 4096), NULL, NULL, 0, + user_pt); + + if(ret) { + ETRACE("wsbmBOData failed with error code %d", ret); + /*FIXME: should I unreference this buffer here?*/ + return ret; + } + + *buf = wsbmBuf; + + VTRACE("ttm UB buffer allocated. %p", *buf); + return 0; +} + +int psbWsbmAllocateTTMBuffer(uint32_t size, uint32_t align, void ** buf) +{ + struct _WsbmBufferObject * wsbmBuf = NULL; + int ret = 0; + int offset = 0; + + ATRACE("size %d", align_to(size, 4096)); + + if(!buf) { + ETRACE("invalid parameter"); + return -EINVAL; + } + + VTRACE("mainPool %p", mainPool); + + ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, align, + (WSBM_PL_FLAG_VRAM | WSBM_PL_FLAG_TT | + WSBM_PL_FLAG_SHARED | WSBM_PL_FLAG_NO_EVICT)); + if(ret) { + ETRACE("wsbmGenBuffers failed with error code %d", ret); + return ret; + } + + ret = wsbmBOData(wsbmBuf, align_to(size, 4096), NULL, NULL, 0); + if(ret) { + ETRACE("wsbmBOData failed with error code %d", ret); + /*FIXME: should I unreference this buffer here?*/ + return ret; + } + + /* wsbmBOReference(wsbmBuf); */ /* no need to add reference */ + + *buf = wsbmBuf; + + VTRACE("ttm buffer allocated. %p", *buf); + return 0; +} + +int psbWsbmWrapTTMBuffer(uint64_t handle, void **buf) +{ + int ret = 0; + struct _WsbmBufferObject *wsbmBuf; + + if (!buf) { + ETRACE("invalid parameter"); + return -EINVAL; + } + + ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, 0, + (WSBM_PL_FLAG_VRAM | WSBM_PL_FLAG_TT | + /*WSBM_PL_FLAG_NO_EVICT |*/ WSBM_PL_FLAG_SHARED)); + + if (ret) { + ETRACE("wsbmGenBuffers failed with error code %d", ret); + return ret; + } + + ret = wsbmBOSetReferenced(wsbmBuf, handle); + if (ret) { + ETRACE("wsbmBOSetReferenced failed with error code %d", ret); + return ret; + } + + *buf = (void *)wsbmBuf; + + VTRACE("wrap buffer %p for handle %#x", wsbmBuf, handle); + return 0; +} + +int psbWsbmWrapTTMBuffer2(uint64_t handle, void **buf) +{ + int ret = 0; + struct _WsbmBufferObject *wsbmBuf; + + if (!buf) { + ETRACE("invalid parameter"); + return -EINVAL; + } + + ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, 4096, + (WSBM_PL_FLAG_SHARED | DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_UNCACHED)); + + if (ret) { + ETRACE("wsbmGenBuffers failed with error code %d", ret); + return ret; + } + + *buf = (void *)wsbmBuf; + + VTRACE("wrap buffer %p for handle %#x", wsbmBuf, handle); + return 0; +} + + +int psbWsbmCreateFromUB(void *buf, uint32_t size, void *vaddr) +{ + int ret = 0; + struct _WsbmBufferObject *wsbmBuf; + + if (!buf || !vaddr) { + ETRACE("invalid parameter"); + return -EINVAL; + } + + wsbmBuf = (struct _WsbmBufferObject *)buf; + ret = wsbmBODataUB(wsbmBuf, size, NULL, NULL, 0, vaddr); + if (ret) { + ETRACE("wsbmBODataUB failed with error code %d", ret); + return ret; + } + + return 0; +} + +int psbWsbmUnReference(void *buf) +{ + struct _WsbmBufferObject *wsbmBuf; + + if (!buf) { + ETRACE("invalid parameter"); + return -EINVAL; + } + + wsbmBuf = (struct _WsbmBufferObject *)buf; + + wsbmBOUnreference(&wsbmBuf); + + return 0; +} + +int psbWsbmDestroyTTMBuffer(void * buf) +{ + CTRACE(); + + if(!buf) { + ETRACE("invalid ttm buffer"); + return -EINVAL; + } + + /*FIXME: should I unmap this buffer object first?*/ + wsbmBOUnmap((struct _WsbmBufferObject *)buf); + + wsbmBOUnreference((struct _WsbmBufferObject **)&buf); + + XTRACE(); + + return 0; +} + +void * psbWsbmGetCPUAddress(void * buf) +{ + if(!buf) { + ETRACE("invalid ttm buffer"); + return NULL; + } + + VTRACE("buffer object %p", buf); + + void * address = wsbmBOMap((struct _WsbmBufferObject *)buf, + WSBM_ACCESS_READ | WSBM_ACCESS_WRITE); + if(!address) { + ETRACE("failed to map buffer object"); + return NULL; + } + + VTRACE("mapped successfully. %p, size %ld", + address, wsbmBOSize((struct _WsbmBufferObject *)buf)); + + return address; +} + +uint32_t psbWsbmGetGttOffset(void * buf) +{ + if(!buf) { + ETRACE("invalid ttm buffer"); + return 0; + } + + VTRACE("buffer object %p", buf); + + uint32_t offset = + wsbmBOOffsetHint((struct _WsbmBufferObject *)buf) - 0x10000000; + + VTRACE("offset %#x", offset >> 12); + + return offset >> 12; +} + +uint32_t psbWsbmGetKBufHandle(void *buf) +{ + if (!buf) { + ETRACE("invalid ttm buffer"); + return 0; + } + + return (wsbmKBufHandle(wsbmKBuf((struct _WsbmBufferObject *)buf))); +} + +uint32_t psbWsbmWaitIdle(void *buf) +{ + if (!buf) { + ETRACE("invalid ttm buffer"); + return -EINVAL; + } + + wsbmBOWaitIdle(buf, 0); + return 0; +} diff --git a/merrifield/ips/common/WsbmWrapper.h b/merrifield/ips/common/WsbmWrapper.h new file mode 100644 index 0000000..1dad5fd --- /dev/null +++ b/merrifield/ips/common/WsbmWrapper.h @@ -0,0 +1,41 @@ +/* +// 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. +*/ +#ifndef WSBM_WRAPPER_H +#define WSBM_WRAPPER_H + +#if defined(__cplusplus) +extern "C" { +#endif + +extern int psbWsbmInitialize(int drmFD); +extern void psbWsbmTakedown(); +extern int psbWsbmAllocateFromUB(uint32_t size, uint32_t align, void ** buf, void *user_pt); +extern int psbWsbmAllocateTTMBuffer(uint32_t size, uint32_t align,void ** buf); +extern int psbWsbmDestroyTTMBuffer(void * buf); +extern void * psbWsbmGetCPUAddress(void * buf); +extern uint32_t psbWsbmGetGttOffset(void * buf); +extern int psbWsbmWrapTTMBuffer(uint64_t handle, void **buf); +extern int psbWsbmWrapTTMBuffer2(uint64_t handle, void **buf); +extern int psbWsbmCreateFromUB(void *buf, uint32_t size, void *vaddr); +extern int psbWsbmUnReference(void *buf); +extern int psbWsbmWaitIdle(void *buf); +uint32_t psbWsbmGetKBufHandle(void *buf); + +#if defined(__cplusplus) +} +#endif + +#endif /*WSBM_WRAPPER_H*/ diff --git a/merrifield/ips/penwell/PnwGrallocBuffer.cpp b/merrifield/ips/penwell/PnwGrallocBuffer.cpp new file mode 100644 index 0000000..a867cb8 --- /dev/null +++ b/merrifield/ips/penwell/PnwGrallocBuffer.cpp @@ -0,0 +1,46 @@ +/* +// 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 <penwell/PnwGrallocBuffer.h> + +namespace android { +namespace intel { + +PnwGrallocBuffer::PnwGrallocBuffer(uint32_t handle) + :GrallocBufferBase(handle) +{ + struct PnwIMGGrallocBuffer *grallocHandle = + (struct PnwIMGGrallocBuffer*)handle; + + CTRACE(); + + if (!grallocHandle) { + ETRACE("gralloc handle is null"); + return; + } + + mFormat = grallocHandle->format; + mWidth = grallocHandle->width; + mHeight = grallocHandle->height; + mUsage = grallocHandle->usage; + mKey = grallocHandle->stamp; + mBpp = grallocHandle->bpp; + + initialize(); +} + +} +} diff --git a/merrifield/ips/penwell/PnwGrallocBuffer.h b/merrifield/ips/penwell/PnwGrallocBuffer.h new file mode 100644 index 0000000..ce0414c --- /dev/null +++ b/merrifield/ips/penwell/PnwGrallocBuffer.h @@ -0,0 +1,46 @@ +/* +// 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. +*/ +#ifndef PNW_GRALLOC_BUFFER_H +#define PNW_GRALLOC_BUFFER_H + +#include <common/GrallocSubBuffer.h> +#include <common/GrallocBufferBase.h> + +namespace android { +namespace intel { + +struct PnwIMGGrallocBuffer{ + native_handle_t base; + int fd[SUB_BUFFER_MAX]; + unsigned long long stamp; + int usage; + int width; + int height; + int format; + int bpp; +}__attribute__((aligned(sizeof(int)),packed)); + + +class PnwGrallocBuffer : public GrallocBufferBase { +public: + PnwGrallocBuffer(uint32_t handle); +}; + +} // namespace intel +} // namespace android + + +#endif /* PNW_GRALLOC_BUFFER_H */ diff --git a/merrifield/ips/penwell/PnwGrallocBufferMapper.cpp b/merrifield/ips/penwell/PnwGrallocBufferMapper.cpp new file mode 100644 index 0000000..2550437 --- /dev/null +++ b/merrifield/ips/penwell/PnwGrallocBufferMapper.cpp @@ -0,0 +1,48 @@ +/* +// 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 <Drm.h> +#include <Hwcomposer.h> +#include <penwell/PnwGrallocBufferMapper.h> + +namespace android { +namespace intel { + +PnwGrallocBufferMapper::PnwGrallocBufferMapper(DataBuffer& buffer) + : GrallocBufferMapperBase(buffer) +{ + CTRACE(); +} + +PnwGrallocBufferMapper::~PnwGrallocBufferMapper() +{ + CTRACE(); +} + +bool PnwGrallocBufferMapper::map() +{ + // TODO: implement map + return false; +} + +bool PnwGrallocBufferMapper::unmap() +{ + //TODO: implement unmap + return false; +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/penwell/PnwGrallocBufferMapper.h b/merrifield/ips/penwell/PnwGrallocBufferMapper.h new file mode 100644 index 0000000..743d498 --- /dev/null +++ b/merrifield/ips/penwell/PnwGrallocBufferMapper.h @@ -0,0 +1,38 @@ +/* +// 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. +*/ +#ifndef PNW_GRALLOC_BUFFER_MAPPER_H +#define PNW_GRALLOC_BUFFER_MAPPER_H + +#include <BufferMapper.h> +#include <hal_public.h> +#include <common/GrallocBufferMapperBase.h> + +namespace android { +namespace intel { + +class PnwGrallocBufferMapper : public GrallocBufferMapperBase { +public: + PnwGrallocBufferMapper(DataBuffer& buffer); + ~PnwGrallocBufferMapper(); +public: + bool map(); + bool unmap(); +}; + +} // namespace intel +} // namespace android + +#endif /* TNG_GRALLOC_BUFFER_MAPPER_H */ diff --git a/merrifield/ips/penwell/PnwOverlayPlane.cpp b/merrifield/ips/penwell/PnwOverlayPlane.cpp new file mode 100644 index 0000000..f2328fa --- /dev/null +++ b/merrifield/ips/penwell/PnwOverlayPlane.cpp @@ -0,0 +1,51 @@ +/* +// 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 <penwell/PnwOverlayPlane.h> +#include <penwell/PnwGrallocBuffer.h> + +namespace android { +namespace intel { + +PnwOverlayPlane::PnwOverlayPlane(int index, int disp) + : OverlayPlaneBase(index, disp) +{ + CTRACE(); +} + +PnwOverlayPlane::~PnwOverlayPlane() +{ + CTRACE(); +} + +bool PnwOverlayPlane::flip() +{ + //TODO: implement flip + return false; +} + +void* PnwOverlayPlane::getContext() const +{ + CTRACE(); + //TODO: return penwell overlay context + return 0; +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/penwell/PnwOverlayPlane.h b/merrifield/ips/penwell/PnwOverlayPlane.h new file mode 100644 index 0000000..0ae3924 --- /dev/null +++ b/merrifield/ips/penwell/PnwOverlayPlane.h @@ -0,0 +1,42 @@ +/* +// 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. +*/ +#ifndef PNW_OVERLAY_PLANE_H +#define PNW_OVERLAY_PLANE_H + +#include <utils/KeyedVector.h> +#include <hal_public.h> +#include <DisplayPlane.h> +#include <BufferMapper.h> +#include <common/Wsbm.h> +#include <common/OverlayPlaneBase.h> + +namespace android { +namespace intel { + +class PnwOverlayPlane : public OverlayPlaneBase { + +public: + PnwOverlayPlane(int index, int disp); + ~PnwOverlayPlane(); + + virtual bool flip(); + virtual void* getContext() const; +}; + +} // namespace intel +} // namespace android + +#endif /* PNW_OVERLAY_PLANE_H */ diff --git a/merrifield/ips/penwell/PnwPrimaryPlane.cpp b/merrifield/ips/penwell/PnwPrimaryPlane.cpp new file mode 100644 index 0000000..c88d116 --- /dev/null +++ b/merrifield/ips/penwell/PnwPrimaryPlane.cpp @@ -0,0 +1,65 @@ +/* +// 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 <Drm.h> +#include <penwell/PnwPrimaryPlane.h> +#include <penwell/PnwGrallocBuffer.h> +#include <common/PixelFormat.h> + +namespace android { +namespace intel { + +PnwPrimaryPlane::PnwPrimaryPlane(int index, int disp) + : PnwSpritePlane(index, disp) +{ + CTRACE(); + mType = PLANE_PRIMARY; +} + +PnwPrimaryPlane::~PnwPrimaryPlane() +{ + CTRACE(); +} + +void PnwPrimaryPlane::setFramebufferTarget(DataBuffer& buf) +{ + CTRACE(); + //TODO: implement penwell frame buffer target flip +} + +bool PnwPrimaryPlane::setDataBuffer(uint32_t handle) +{ + PnwGrallocBuffer tmpBuf(handle); + uint32_t usage; + + ATRACE("handle = %#x", handle); + + usage = tmpBuf.getUsage(); + if (!handle || (GRALLOC_USAGE_HW_FB & usage)) { + setFramebufferTarget(tmpBuf); + return true; + } + + return DisplayPlane::setDataBuffer(handle); +} + +bool PnwPrimaryPlane::assignToDevice(int disp) +{ + return true; +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/penwell/PnwPrimaryPlane.h b/merrifield/ips/penwell/PnwPrimaryPlane.h new file mode 100644 index 0000000..7f8b443 --- /dev/null +++ b/merrifield/ips/penwell/PnwPrimaryPlane.h @@ -0,0 +1,38 @@ +/* +// 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. +*/ +#ifndef PNW_PRIMARY_PLANE_H +#define PNW_PRIMARY_PLANE_H + +#include <penwell/PnwSpritePlane.h> + +namespace android { +namespace intel { + +class PnwPrimaryPlane : public PnwSpritePlane { +public: + PnwPrimaryPlane(int index, int disp); + ~PnwPrimaryPlane(); +public: + bool setDataBuffer(uint32_t handle); + bool assignToDevice(int disp); +private: + void setFramebufferTarget(DataBuffer& buf); +}; + +} // namespace intel +} // namespace android + +#endif /* TNG_PRIMARY_PLANE_H */ diff --git a/merrifield/ips/penwell/PnwSpritePlane.cpp b/merrifield/ips/penwell/PnwSpritePlane.cpp new file mode 100644 index 0000000..6799b1a --- /dev/null +++ b/merrifield/ips/penwell/PnwSpritePlane.cpp @@ -0,0 +1,50 @@ +/* +// 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 <Hwcomposer.h> +#include <BufferManager.h> +#include <penwell/PnwSpritePlane.h> +#include <common/PixelFormat.h> + +namespace android { +namespace intel { + +PnwSpritePlane::PnwSpritePlane(int index, int disp) + : SpritePlaneBase(index, disp) +{ + CTRACE(); +} + +PnwSpritePlane::~PnwSpritePlane() +{ + CTRACE(); +} + +bool PnwSpritePlane::setDataBuffer(BufferMapper& mapper) +{ + // TODO: implement setDataBuffer + return false; +} + +void* PnwSpritePlane::getContext() const +{ + CTRACE(); + // TODO: return penwell sprite context + return 0; +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/penwell/PnwSpritePlane.h b/merrifield/ips/penwell/PnwSpritePlane.h new file mode 100644 index 0000000..189ef1b --- /dev/null +++ b/merrifield/ips/penwell/PnwSpritePlane.h @@ -0,0 +1,42 @@ +/* +// 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. +*/ +#ifndef PNW_SPRITE_PLANE_H +#define PNW_SPRITE_PLANE_H + +#include <utils/KeyedVector.h> +#include <hal_public.h> +#include <BufferCache.h> +#include <DisplayPlane.h> + +#include <common/SpritePlaneBase.h> + +namespace android { +namespace intel { + +class PnwSpritePlane : public SpritePlaneBase { +public: + PnwSpritePlane(int index, int disp); + virtual ~PnwSpritePlane(); +public: + virtual void* getContext() const; +protected: + virtual bool setDataBuffer(BufferMapper& mapper); +}; + +} // namespace intel +} // namespace android + +#endif /* PNW_SPRITE_PLANE_H */ diff --git a/merrifield/ips/tangier/TngCursorPlane.cpp b/merrifield/ips/tangier/TngCursorPlane.cpp new file mode 100644 index 0000000..8ce5af7 --- /dev/null +++ b/merrifield/ips/tangier/TngCursorPlane.cpp @@ -0,0 +1,244 @@ +/* +// 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 <Hwcomposer.h> +#include <BufferManager.h> +#include <BufferManager.h> +#include <tangier/TngCursorPlane.h> +#include <tangier/TngGrallocBuffer.h> +#include <hal_public.h> + +namespace android { +namespace intel { + +TngCursorPlane::TngCursorPlane(int index, int disp) + : DisplayPlane(index, PLANE_CURSOR, disp) +{ + CTRACE(); + memset(&mContext, 0, sizeof(mContext)); + memset(&mCrop, 0, sizeof(mCrop)); +} + +TngCursorPlane::~TngCursorPlane() +{ + CTRACE(); +} + +bool TngCursorPlane::enable() +{ + return enablePlane(true); +} + +bool TngCursorPlane::disable() +{ + return enablePlane(false); +} + +void* TngCursorPlane::getContext() const +{ + CTRACE(); + return (void *)&mContext; +} + +void TngCursorPlane::setZOrderConfig(ZOrderConfig& config, void *nativeConfig) +{ + (void) config; + (void) nativeConfig; + + VTRACE("\n *** need to implement zorder config *** "); + CTRACE(); +} + +bool TngCursorPlane::setDataBuffer(buffer_handle_t handle) +{ + bool ret; + + if (!handle) { + ETRACE("handle is NULL"); + return false; + } + + ret = DisplayPlane::setDataBuffer(handle); + if (ret == false) { + ETRACE("failed to set data buffer"); + return ret; + } + + return true; +} + +bool TngCursorPlane::setDataBuffer(BufferMapper& mapper) +{ + int w = mapper.getWidth(); + int h = mapper.getHeight(); + int cursorSize = 0; + + CTRACE(); + + // setup plane position + int dstX = mPosition.x; + int dstY = mPosition.y; + + if (h < w) { + cursorSize = h; + } else { + cursorSize = w; + } + + uint32_t cntr = 0; + if (64 <= cursorSize && cursorSize < 128) { + cursorSize = 64; + cntr = 0x7; + } else if (128 <= cursorSize && cursorSize < 256) { + cursorSize = 128; + cntr = 0x2; + } else { + cursorSize = 256; + cntr = 0x3; + } + + if (mapper.getFormat() == HAL_PIXEL_FORMAT_RGBA_8888) { + cntr |= 1 << 5; + } else if (mapper.getFormat() == HAL_PIXEL_FORMAT_BGRA_8888) { + // swap color from BGRA to RGBA - alpha is MSB + uint8_t *p = (uint8_t *)(mapper.getCpuAddress(0)); + uint8_t *srcPixel; + uint32_t stride = mapper.getStride().rgb.stride; + uint8_t temp; + if (!p) { + return false; + } + + for (int i = 0; i < cursorSize; i++) { + for (int j = 0; j < cursorSize; j++) { + srcPixel = p + i*stride + j*4; + temp = srcPixel[0]; + srcPixel[0] = srcPixel[2]; + srcPixel[2] = temp; + } + } + cntr |= 1 << 5; + } else { + ETRACE("invalid color format"); + return false; + } + + // TODO: clean spare mem to be 0 in gralloc instead + uint8_t *p = (uint8_t *)(mapper.getCpuAddress(0)); + uint8_t *srcPixel; + uint32_t stride = mapper.getStride().rgb.stride; + uint8_t temp; + if (!p) { + return false; + } + + if (mCrop.w == 0 && mCrop.h == 0) { + mCrop = mSrcCrop; + for (int i = 0; i < cursorSize; i++) { + for (int j = 0; j < cursorSize; j++) { + srcPixel = p + i*stride + j*4; + temp = srcPixel[0]; + if (i >= mCrop.h || j >= mCrop.w) { + if (srcPixel[0] == 0 && + srcPixel[3] == 0xff) + srcPixel[3] = 0; + } + } + } + } + + // update context + mContext.type = DC_CURSOR_PLANE; + mContext.ctx.cs_ctx.index = mIndex; + mContext.ctx.cs_ctx.pipe = mDevice; + mContext.ctx.cs_ctx.cntr = cntr | (mIndex << 28); + mContext.ctx.cs_ctx.surf = mapper.getGttOffsetInPage(0) << 12; + + mContext.ctx.cs_ctx.pos = 0; + if (dstX < 0) { + mContext.ctx.cs_ctx.pos |= 1 << 15; + dstX = -dstX; + } + if (dstY < 0) { + mContext.ctx.cs_ctx.pos |= 1 << 31; + dstY = -dstY; + } + mContext.ctx.cs_ctx.pos |= (dstY & 0xfff) << 16 | (dstX & 0xfff); + return true; +} + +bool TngCursorPlane::enablePlane(bool enabled) +{ + RETURN_FALSE_IF_NOT_INIT(); + + struct drm_psb_register_rw_arg arg; + memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); + if (enabled) { + arg.plane_enable_mask = 1; + } else { + arg.plane_disable_mask = 1; + } + + arg.plane.type = DC_CURSOR_PLANE; + arg.plane.index = mIndex; + arg.plane.ctx = 0; + + // issue ioctl + Drm *drm = Hwcomposer::getInstance().getDrm(); + bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); + if (ret == false) { + WTRACE("plane enabling (%d) failed with error code %d", enabled, ret); + return false; + } + + return true; +} + +bool TngCursorPlane::isDisabled() +{ + RETURN_FALSE_IF_NOT_INIT(); + + struct drm_psb_register_rw_arg arg; + memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); + + arg.plane.type = DC_CURSOR_PLANE; + arg.get_plane_state_mask = 1; + arg.plane.index = mIndex; + arg.plane.ctx = 0; + + // issue ioctl + Drm *drm = Hwcomposer::getInstance().getDrm(); + bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); + if (ret == false) { + WTRACE("plane state query failed with error code %d", ret); + return false; + } + + return arg.plane.ctx == PSB_DC_PLANE_DISABLED; + //return arg.plane.ctx == 0; //implement this PSB_DC_PLANE_DISABLED similar in imin_legacy + + return true; +} + +void TngCursorPlane::postFlip() +{ + // prevent mUpdateMasks from being reset + // skipping flip may cause flicking +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/tangier/TngCursorPlane.h b/merrifield/ips/tangier/TngCursorPlane.h new file mode 100644 index 0000000..85e869a --- /dev/null +++ b/merrifield/ips/tangier/TngCursorPlane.h @@ -0,0 +1,58 @@ +/* +// 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. +*/ + +#ifndef TNG_CUR_PLANE_H +#define TNG_CUR_PLANE_H + +#include <utils/KeyedVector.h> +#include <hal_public.h> +#include <Hwcomposer.h> +#include <BufferCache.h> +#include <DisplayPlane.h> + +#include <linux/psb_drm.h> + +namespace android { +namespace intel { + +class TngCursorPlane : public DisplayPlane { +public: + TngCursorPlane(int index, int disp); + virtual ~TngCursorPlane(); +public: + // hardware operations + bool enable(); + bool disable(); + bool isDisabled(); + void postFlip(); + + void* getContext() const; + void setZOrderConfig(ZOrderConfig& config, void *nativeConfig); + + bool setDataBuffer(buffer_handle_t handle); +protected: + bool setDataBuffer(BufferMapper& mapper); + bool enablePlane(bool enabled); + +protected: + struct intel_dc_plane_ctx mContext; + crop_t mCrop; +}; + +} // namespace intel +} // namespace android + +#endif /* TNG_CUR_PLANE_H */ diff --git a/merrifield/ips/tangier/TngDisplayContext.cpp b/merrifield/ips/tangier/TngDisplayContext.cpp new file mode 100644 index 0000000..7f94185 --- /dev/null +++ b/merrifield/ips/tangier/TngDisplayContext.cpp @@ -0,0 +1,278 @@ +/* +// 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 <Hwcomposer.h> +#include <Drm.h> +#include <DisplayPlane.h> +#include <IDisplayDevice.h> +#include <HwcLayerList.h> +#include <tangier/TngDisplayContext.h> + + +namespace android { +namespace intel { + +TngDisplayContext::TngDisplayContext() + : mIMGDisplayDevice(0), + mInitialized(false), + mCount(0) +{ + CTRACE(); +} + +TngDisplayContext::~TngDisplayContext() +{ + WARN_IF_NOT_DEINIT(); +} + +bool TngDisplayContext::initialize() +{ + CTRACE(); + + // open frame buffer device + hw_module_t const* module; + int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); + if (err) { + ETRACE("failed to load gralloc module, error = %d", err); + return false; + } + + // init IMG display device + mIMGDisplayDevice = (((IMG_gralloc_module_public_t *)module)->getDisplayDevice((IMG_gralloc_module_public_t *)module)); + if (!mIMGDisplayDevice) { + ETRACE("failed to get display device"); + return false; + } + + mCount = 0; + mInitialized = true; + return true; +} + +bool TngDisplayContext::commitBegin(size_t numDisplays, hwc_display_contents_1_t **displays) +{ + RETURN_FALSE_IF_NOT_INIT(); + mCount = 0; + return true; +} + +bool TngDisplayContext::commitContents(hwc_display_contents_1_t *display, HwcLayerList *layerList) +{ + bool ret; + + RETURN_FALSE_IF_NOT_INIT(); + + if (!display || !layerList) { + ETRACE("invalid parameters"); + return false; + } + + IMG_hwc_layer_t *imgLayerList = (IMG_hwc_layer_t*)mImgLayers; + + for (size_t i = 0; i < display->numHwLayers; i++) { + if (mCount >= MAXIMUM_LAYER_NUMBER) { + ETRACE("layer count exceeds the limit"); + return false; + } + + // check layer parameters + if (!display->hwLayers[i].handle) { + continue; + } + + DisplayPlane* plane = layerList->getPlane(i); + if (!plane) { + continue; + } + + ret = plane->flip(NULL); + if (ret == false) { + VTRACE("failed to flip plane %d", i); + continue; + } + + IMG_hwc_layer_t *imgLayer = &imgLayerList[mCount++]; + // update IMG layer + imgLayer->psLayer = &display->hwLayers[i]; + imgLayer->custom = (unsigned long)plane->getContext(); + struct intel_dc_plane_ctx *ctx = + (struct intel_dc_plane_ctx *)imgLayer->custom; + // update z order + Hwcomposer& hwc = Hwcomposer::getInstance(); + DisplayPlaneManager *pm = hwc.getPlaneManager(); + void *config = pm->getZOrderConfig(); + if (config) { + memcpy(&ctx->zorder, config, sizeof(ctx->zorder)); + } else { + memset(&ctx->zorder, 0, sizeof(ctx->zorder)); + } + + VTRACE("count %p, handle %#x, trans %#x, blending %#x" + " sourceCrop %f,%f - %fx%f, dst %d,%d - %dx%d, custom %#x", + mCount, + imgLayer->psLayer->handle, + imgLayer->psLayer->transform, + imgLayer->psLayer->blending, + imgLayer->psLayer->sourceCropf.left, + imgLayer->psLayer->sourceCropf.top, + imgLayer->psLayer->sourceCropf.right - imgLayer->psLayer->sourceCropf.left, + imgLayer->psLayer->sourceCropf.bottom - imgLayer->psLayer->sourceCropf.top, + imgLayer->psLayer->displayFrame.left, + imgLayer->psLayer->displayFrame.top, + imgLayer->psLayer->displayFrame.right - imgLayer->psLayer->displayFrame.left, + imgLayer->psLayer->displayFrame.bottom - imgLayer->psLayer->displayFrame.top, + imgLayer->custom); + } + + layerList->postFlip(); + return true; +} + +bool TngDisplayContext::commitEnd(size_t numDisplays, hwc_display_contents_1_t **displays) +{ + int releaseFenceFd = -1; + + VTRACE("count = %d", mCount); + + if (mIMGDisplayDevice && mCount) { + int err = mIMGDisplayDevice->post(mIMGDisplayDevice, + mImgLayers, + mCount, + &releaseFenceFd); + if (err) { + ETRACE("post failed, err = %d", err); + return false; + } + } + + // close acquire fence + for (size_t i = 0; i < numDisplays; i++) { + // Wait and close HWC_OVERLAY typed layer's acquire fence + hwc_display_contents_1_t* display = displays[i]; + if (!display) { + continue; + } + + for (size_t j = 0; j < display->numHwLayers-1; j++) { + hwc_layer_1_t& layer = display->hwLayers[j]; + if (layer.compositionType == HWC_OVERLAY) { + if (layer.acquireFenceFd != -1) { + // sync_wait(layer.acquireFenceFd, 16ms); + close(layer.acquireFenceFd); + layer.acquireFenceFd = -1; + } + } + } + + // Wait and close framebuffer target layer's acquire fence + hwc_layer_1_t& fbt = display->hwLayers[display->numHwLayers-1]; + if (fbt.acquireFenceFd != -1) { + // sync_wait(fbt.acquireFencdFd, 16ms); + close(fbt.acquireFenceFd); + fbt.acquireFenceFd = -1; + } + + // Wait and close outbuf's acquire fence + if (display->outbufAcquireFenceFd != -1) { + // sync_wait(display->outbufAcquireFenceFd, 16ms); + close(display->outbufAcquireFenceFd); + display->outbufAcquireFenceFd = -1; + } + } + + // update release fence and retire fence + if (mCount > 0) { + // For physical displays, dup the releaseFenceFd only for + // HWC layers which successfully flipped to display planes + IMG_hwc_layer_t *imgLayerList = (IMG_hwc_layer_t*)mImgLayers; + + for (unsigned int i = 0; i < mCount; i++) { + IMG_hwc_layer_t *imgLayer = &imgLayerList[i]; + imgLayer->psLayer->releaseFenceFd = + (releaseFenceFd != -1) ? dup(releaseFenceFd) : -1; + } + } + + for (size_t i = 0; i < numDisplays; i++) { + if (!displays[i]) { + continue; + } + + // log for layer fence status + for (size_t j = 0; j < displays[i]->numHwLayers; j++) { + VTRACE("handle %#p, acquiredFD %d, releaseFD %d", + displays[i]->hwLayers[j].handle, + displays[i]->hwLayers[j].acquireFenceFd, + displays[i]->hwLayers[j].releaseFenceFd); + } + +#ifdef INTEL_WIDI_MERRIFIELD + // retireFence is used for SurfaceFlinger to do DispSync; + // dup releaseFenceFd for physical displays and ignore virtual + // display; we don't distinguish between release and retire, and all + // physical displays are using a single releaseFence; for virtual + // display, fencing is handled by the VirtualDisplay class + if (i < IDisplayDevice::DEVICE_VIRTUAL) { +#endif + displays[i]->retireFenceFd = + (releaseFenceFd != -1) ? dup(releaseFenceFd) : -1; +#ifdef INTEL_WIDI_MERRIFIELD + } +#endif + } + + // close original release fence fd + if (releaseFenceFd != -1) { + close(releaseFenceFd); + } + return true; +} + +bool TngDisplayContext::compositionComplete() +{ + return true; +} + +bool TngDisplayContext::setCursorPosition(int disp, int x, int y) +{ + DTRACE("setCursorPosition"); + struct intel_dc_cursor_ctx ctx; + memset(&ctx, 0, sizeof(ctx)); + ctx.pipe = disp; + if (x < 0) { + ctx.pos |= 1 << 15; + x = -x; + } + if (y < 0) { + ctx.pos |= 1 << 31; + y = -y; + } + ctx.pos |= (y & 0xfff) << 16 | (x & 0xfff); + Drm *drm = Hwcomposer::getInstance().getDrm(); + return drm->writeIoctl(DRM_PSB_UPDATE_CURSOR_POS, &ctx, sizeof(ctx)); +} + +void TngDisplayContext::deinitialize() +{ + mIMGDisplayDevice = 0; + + mCount = 0; + mInitialized = false; +} + + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/tangier/TngDisplayContext.h b/merrifield/ips/tangier/TngDisplayContext.h new file mode 100644 index 0000000..fa526d7 --- /dev/null +++ b/merrifield/ips/tangier/TngDisplayContext.h @@ -0,0 +1,51 @@ +/* +// 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. +*/ +#ifndef TNG_DISPLAY_CONTEXT_H +#define TNG_DISPLAY_CONTEXT_H + +#include <IDisplayContext.h> +#include <hal_public.h> + +namespace android { +namespace intel { + +class TngDisplayContext : public IDisplayContext { +public: + TngDisplayContext(); + virtual ~TngDisplayContext(); +public: + bool initialize(); + void deinitialize(); + bool commitBegin(size_t numDisplays, hwc_display_contents_1_t **displays); + bool commitContents(hwc_display_contents_1_t *display, HwcLayerList* layerList); + bool commitEnd(size_t numDisplays, hwc_display_contents_1_t **displays); + bool compositionComplete(); + bool setCursorPosition(int disp, int x, int y); + +private: + enum { + MAXIMUM_LAYER_NUMBER = 20, + }; + IMG_display_device_public_t *mIMGDisplayDevice; + IMG_hwc_layer_t mImgLayers[MAXIMUM_LAYER_NUMBER]; + bool mInitialized; + size_t mCount; +}; + +} // namespace intel +} // namespace android + +#endif /* TNG_DISPLAY_CONTEXT_H */ diff --git a/merrifield/ips/tangier/TngDisplayQuery.cpp b/merrifield/ips/tangier/TngDisplayQuery.cpp new file mode 100644 index 0000000..c25aecf --- /dev/null +++ b/merrifield/ips/tangier/TngDisplayQuery.cpp @@ -0,0 +1,63 @@ +/* +// 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 <DisplayQuery.h> + + +namespace android { +namespace intel { + +bool DisplayQuery::isVideoFormat(uint32_t format) +{ + switch (format) { + case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: + case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: + // Expand format to support the case: Software decoder + HW rendering + // Only VP9 use this foramt now + case HAL_PIXEL_FORMAT_YV12: + return true; + default: + return false; + } +} + +int DisplayQuery::getOverlayLumaStrideAlignment(uint32_t format) +{ + // both luma and chroma stride need to be 64-byte aligned for overlay + switch (format) { + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_I420: + // for these two formats, chroma stride is calculated as half of luma stride + // so luma stride needs to be 128-byte aligned. + return 128; + default: + return 64; + } +} + +uint32_t DisplayQuery::queryNV12Format() +{ + return HAL_PIXEL_FORMAT_NV12; +} + +} // namespace intel +} // namespace android + diff --git a/merrifield/ips/tangier/TngGrallocBuffer.cpp b/merrifield/ips/tangier/TngGrallocBuffer.cpp new file mode 100644 index 0000000..b66b896 --- /dev/null +++ b/merrifield/ips/tangier/TngGrallocBuffer.cpp @@ -0,0 +1,62 @@ +/* +// 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 <tangier/TngGrallocBuffer.h> + +namespace android { +namespace intel { + +TngGrallocBuffer::TngGrallocBuffer(buffer_handle_t handle) + :GrallocBufferBase(handle) +{ + initBuffer(handle); +} + +TngGrallocBuffer::~TngGrallocBuffer() +{ +} + +void TngGrallocBuffer::resetBuffer(buffer_handle_t handle) +{ + GrallocBufferBase::resetBuffer(handle); + initBuffer(handle); +} + +void TngGrallocBuffer::initBuffer(buffer_handle_t handle) +{ + TngIMGGrallocBuffer *grallocHandle = (TngIMGGrallocBuffer *)handle; + + CTRACE(); + + if (!grallocHandle) { + ETRACE("gralloc handle is null"); + return; + } + + mFormat = grallocHandle->iFormat; + mWidth = grallocHandle->iWidth; + mHeight = grallocHandle->iHeight; + mUsage = grallocHandle->usage; + mKey = grallocHandle->ui64Stamp; + mBpp = grallocHandle->uiBpp; + + // stride can only be initialized after format is set + initStride(); +} + + +} +} diff --git a/merrifield/ips/tangier/TngGrallocBuffer.h b/merrifield/ips/tangier/TngGrallocBuffer.h new file mode 100644 index 0000000..b528cf8 --- /dev/null +++ b/merrifield/ips/tangier/TngGrallocBuffer.h @@ -0,0 +1,44 @@ +/* +// 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. +*/ +#ifndef TNG_GRALLOC_BUFFER_H +#define TNG_GRALLOC_BUFFER_H + +#include <DataBuffer.h> +#include <hal_public.h> +#include <common/GrallocSubBuffer.h> +#include <common/GrallocBufferBase.h> + +namespace android { +namespace intel { + +typedef IMG_native_handle_t TngIMGGrallocBuffer; + +class TngGrallocBuffer : public GrallocBufferBase { +public: + TngGrallocBuffer(buffer_handle_t handle); + virtual ~TngGrallocBuffer(); + + void resetBuffer(buffer_handle_t handle); + +private: + void initBuffer(buffer_handle_t handle); +}; + +} // namespace intel +} // namespace android + + +#endif /* TNG_GRALLOC_BUFFER_H */ diff --git a/merrifield/ips/tangier/TngGrallocBufferMapper.cpp b/merrifield/ips/tangier/TngGrallocBufferMapper.cpp new file mode 100644 index 0000000..fcf40e7 --- /dev/null +++ b/merrifield/ips/tangier/TngGrallocBufferMapper.cpp @@ -0,0 +1,263 @@ +/* +// 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 <Drm.h> +#include <Hwcomposer.h> +#include <tangier/TngGrallocBufferMapper.h> +#include <common/WsbmWrapper.h> + +namespace android { +namespace intel { + +TngGrallocBufferMapper::TngGrallocBufferMapper(IMG_gralloc_module_public_t& module, + DataBuffer& buffer) + : GrallocBufferMapperBase(buffer), + mIMGGrallocModule(module), + mBufferObject(0) +{ + CTRACE(); + + const native_handle_t *h = (native_handle_t *)mHandle; + + mClonedHandle = native_handle_create(h->numFds, h->numInts); + if (mClonedHandle == 0) { + ALOGE("%s:Failed to create handle, out of memory!"); + return; + } + for (int i = 0; i < h->numFds; i++) + { + mClonedHandle->data[i] = (h->data[i] >= 0) ? dup(h->data[i]) : -1; + } + memcpy(mClonedHandle->data + h->numFds, h->data + h->numFds, h->numInts*sizeof(int)); +} + +TngGrallocBufferMapper::~TngGrallocBufferMapper() +{ + CTRACE(); + + if (mClonedHandle == 0) + return; + native_handle_close(mClonedHandle); + native_handle_delete(mClonedHandle); +} + +bool TngGrallocBufferMapper::gttMap(void *vaddr, + uint32_t size, + uint32_t gttAlign, + int *offset) +{ + struct psb_gtt_mapping_arg arg; + bool ret; + + ATRACE("vaddr = %p, size = %d", vaddr, size); + + if (!vaddr || !size || !offset) { + VTRACE("invalid parameters"); + return false; + } + + arg.type = PSB_GTT_MAP_TYPE_VIRTUAL; + arg.page_align = gttAlign; + arg.vaddr = (unsigned long)vaddr; + arg.size = size; + + Drm *drm = Hwcomposer::getInstance().getDrm(); + ret = drm->writeReadIoctl(DRM_PSB_GTT_MAP, &arg, sizeof(arg)); + if (ret == false) { + ETRACE("gtt mapping failed"); + return false; + } + + VTRACE("offset = %#x", arg.offset_pages); + *offset = arg.offset_pages; + return true; +} + +bool TngGrallocBufferMapper::gttUnmap(void *vaddr) +{ + struct psb_gtt_mapping_arg arg; + bool ret; + + ATRACE("vaddr = %p", vaddr); + + if (!vaddr) { + ETRACE("invalid parameter"); + return false; + } + + arg.type = PSB_GTT_MAP_TYPE_VIRTUAL; + arg.vaddr = (unsigned long)vaddr; + + Drm *drm = Hwcomposer::getInstance().getDrm(); + ret = drm->writeIoctl(DRM_PSB_GTT_UNMAP, &arg, sizeof(arg)); + if (ret == false) { + ETRACE("gtt unmapping failed"); + return false; + } + + return true; +} + +bool TngGrallocBufferMapper::map() +{ + void *vaddr[SUB_BUFFER_MAX]; + uint32_t size[SUB_BUFFER_MAX]; + int gttOffsetInPage = 0; + bool ret; + int err; + int i; + + CTRACE(); + // get virtual address + err = mIMGGrallocModule.getCpuAddress(&mIMGGrallocModule, + (buffer_handle_t)mClonedHandle, + vaddr, + size); + if (err) { + ETRACE("failed to map. err = %d", err); + return false; + } + + for (i = 0; i < SUB_BUFFER_MAX; i++) { + // skip gtt mapping for empty sub buffers + if (!vaddr[i] || !size[i]) + continue; + + // map to gtt + ret = gttMap(vaddr[i], size[i], 0, >tOffsetInPage); + if (!ret) { + VTRACE("failed to map %d into gtt", i); + break; + } + + mCpuAddress[i] = vaddr[i]; + mSize[i] = size[i]; + mGttOffsetInPage[i] = gttOffsetInPage; + // TODO: set kernel handle + mKHandle[i] = 0; + } + + if (i == SUB_BUFFER_MAX) { + return true; + } + + // error handling + for (i = 0; i < SUB_BUFFER_MAX; i++) { + if (mCpuAddress[i]) { + gttUnmap(mCpuAddress[i]); + } + } + + err = mIMGGrallocModule.putCpuAddress(&mIMGGrallocModule, + (buffer_handle_t)mClonedHandle); + return false; +} + +bool TngGrallocBufferMapper::unmap() +{ + int i; + int err; + + CTRACE(); + + for (i = 0; i < SUB_BUFFER_MAX; i++) { + if (mCpuAddress[i]) + gttUnmap(mCpuAddress[i]); + + mGttOffsetInPage[i] = 0; + mCpuAddress[i] = 0; + mSize[i] = 0; + } + + err = mIMGGrallocModule.putCpuAddress(&mIMGGrallocModule, + (buffer_handle_t)mClonedHandle); + if (err) { + ETRACE("failed to unmap. err = %d", err); + } + return err; +} + +buffer_handle_t TngGrallocBufferMapper::getKHandle(int subIndex) +{ + buffer_handle_t ret = GrallocBufferMapperBase::getKHandle(subIndex); + if (subIndex == 0 && ret == 0) { + if (mapKhandle()) + return mKHandle[subIndex]; + } + + return ret; +} + +bool TngGrallocBufferMapper::mapKhandle() +{ + // TODO: this is a complete hack and temporary workaround + // need support from DDK to map khandle + void *wsbmBufferObject = 0; + int ret = psbWsbmWrapTTMBuffer2((uint64_t)mHandle, &wsbmBufferObject); + if (ret != 0) { + ETRACE("Wrap ttm buffer failed!"); + return false; + } + + ret = psbWsbmCreateFromUB(wsbmBufferObject, mWidth * mHeight, mCpuAddress[0]); + if (ret != 0) { + ETRACE("Create from UB failed!"); + return false; + } + + mKHandle[0] = (buffer_handle_t)(unsigned long)psbWsbmGetKBufHandle(wsbmBufferObject); + psbWsbmUnReference(wsbmBufferObject); + return true; +} + +buffer_handle_t TngGrallocBufferMapper::getFbHandle(int subIndex) +{ + void *vaddr[SUB_BUFFER_MAX]; + uint32_t size[SUB_BUFFER_MAX]; + int err; + + CTRACE(); + + if (subIndex < 0 || subIndex >= SUB_BUFFER_MAX) { + return 0; + } + + // get virtual address + err = mIMGGrallocModule.getCpuAddress(&mIMGGrallocModule, + (buffer_handle_t)mClonedHandle, + vaddr, + size); + if (err) { + ETRACE("failed to map. err = %d", err); + return 0; + } + + return (buffer_handle_t)vaddr[subIndex]; +} + +void TngGrallocBufferMapper::putFbHandle() +{ + int err = mIMGGrallocModule.putCpuAddress(&mIMGGrallocModule, + (buffer_handle_t)mClonedHandle); + if (err) { + ETRACE("failed to unmap. err = %d", err); + } + return; + +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/tangier/TngGrallocBufferMapper.h b/merrifield/ips/tangier/TngGrallocBufferMapper.h new file mode 100644 index 0000000..d72005e --- /dev/null +++ b/merrifield/ips/tangier/TngGrallocBufferMapper.h @@ -0,0 +1,52 @@ +/* +// 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. +*/ +#ifndef TNG_GRALLOC_BUFFER_MAPPER_H +#define TNG_GRALLOC_BUFFER_MAPPER_H + +#include <BufferMapper.h> +#include <hal_public.h> +#include <common/GrallocBufferMapperBase.h> +#include <tangier/TngGrallocBuffer.h> + +namespace android { +namespace intel { + +class TngGrallocBufferMapper : public GrallocBufferMapperBase { +public: + TngGrallocBufferMapper(IMG_gralloc_module_public_t& module, + DataBuffer& buffer); + virtual ~TngGrallocBufferMapper(); +public: + bool map(); + bool unmap(); + buffer_handle_t getKHandle(int subIndex); + buffer_handle_t getFbHandle(int subIndex); + void putFbHandle(); +private: + bool gttMap(void *vaddr, uint32_t size, uint32_t gttAlign, int *offset); + bool gttUnmap(void *vaddr); + bool mapKhandle(); + +private: + IMG_gralloc_module_public_t& mIMGGrallocModule; + void* mBufferObject; + native_handle_t* mClonedHandle; +}; + +} // namespace intel +} // namespace android + +#endif /* TNG_GRALLOC_BUFFER_MAPPER_H */ diff --git a/merrifield/ips/tangier/TngOverlayPlane.cpp b/merrifield/ips/tangier/TngOverlayPlane.cpp new file mode 100644 index 0000000..d837015 --- /dev/null +++ b/merrifield/ips/tangier/TngOverlayPlane.cpp @@ -0,0 +1,218 @@ +/* +// 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 <tangier/TngOverlayPlane.h> +#include <tangier/TngGrallocBuffer.h> + +namespace android { +namespace intel { + +TngOverlayPlane::TngOverlayPlane(int index, int disp) + : OverlayPlaneBase(index, disp), + mRotationBufProvider(NULL) +{ + CTRACE(); + + memset(&mContext, 0, sizeof(mContext)); +} + +TngOverlayPlane::~TngOverlayPlane() +{ + CTRACE(); +} + +bool TngOverlayPlane::flip(void *ctx) +{ + RETURN_FALSE_IF_NOT_INIT(); + + if (!DisplayPlane::flip(ctx)) + return false; + + mContext.type = DC_OVERLAY_PLANE; + mContext.ctx.ov_ctx.ovadd = 0x0; + mContext.ctx.ov_ctx.ovadd = (mBackBuffer[mCurrent]->gttOffsetInPage << 12); + mContext.ctx.ov_ctx.index = mIndex; + mContext.ctx.ov_ctx.pipe = mDevice; + mContext.ctx.ov_ctx.ovadd |= mPipeConfig; + mContext.ctx.ov_ctx.ovadd |= 0x1; + + // 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; +} + +bool TngOverlayPlane::reset() +{ + OverlayPlaneBase::reset(); + if (mRotationBufProvider) + mRotationBufProvider->reset(); + return true; +} + +void* TngOverlayPlane::getContext() const +{ + CTRACE(); + return (void *)&mContext; +} + +bool TngOverlayPlane::setDataBuffer(BufferMapper& mapper) +{ + if (OverlayPlaneBase::setDataBuffer(mapper) == false) { + return false; + } + + 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 = (uint64_t)mapper.getCpuAddress(0); + return true; +} + +bool TngOverlayPlane::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 TngOverlayPlane::deinitialize() +{ + DEINIT_AND_DELETE_OBJ(mRotationBufProvider); + OverlayPlaneBase::deinitialize(); +} + +bool TngOverlayPlane::rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper) +{ + struct VideoPayloadBuffer *payload; + VideoPayloadBuffer buffer_info; + uint32_t format; + // only NV12_VED has rotated buffer + format = mapper.getFormat(); + + if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar && + format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled && + format != HAL_PIXEL_FORMAT_NV12) { + ETRACE("Invalid video format %#x", format); + return false; + } + + payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1); + + if (payload == NULL && format == HAL_PIXEL_FORMAT_NV12) { + // need to populate buffer_info + void *p = mapper.getCpuAddress(SUB_BUFFER0); + if (!p) { + ETRACE("failed to get buffer user pointer"); + return false; + } + + bool ret = mRotationBufProvider->prepareBufferInfo(mapper.getWidth(), + mapper.getHeight(), + mapper.getStride().yuv.yStride, + &buffer_info, p); + if (ret == false) { + ETRACE("failed to prepare buffer info"); + return false; + } + payload = &buffer_info; + } + + // 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) { + payload->hwc_timestamp = systemTime(); + payload->layer_transform = mTransform; + if (!mRotationBufProvider->setupRotationBuffer(payload, mTransform)) { + ETRACE("failed to setup rotation buffer"); + return false; + } + } + + rotatedMapper = getTTMMapper(mapper, payload); + + return true; +} + +bool TngOverlayPlane::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)) + 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 = (mBackBuffer[mCurrent]->gttOffsetInPage << 12); + // pipe select + arg.plane.ctx |= mPipeConfig; + + 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 diff --git a/merrifield/ips/tangier/TngOverlayPlane.h b/merrifield/ips/tangier/TngOverlayPlane.h new file mode 100644 index 0000000..9129965 --- /dev/null +++ b/merrifield/ips/tangier/TngOverlayPlane.h @@ -0,0 +1,55 @@ +/* +// 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. +*/ +#ifndef TNG_OVERLAY_PLANE_H +#define TNG_OVERLAY_PLANE_H + +#include <utils/KeyedVector.h> +#include <hal_public.h> +#include <DisplayPlane.h> +#include <BufferMapper.h> +#include <common/Wsbm.h> +#include <common/OverlayPlaneBase.h> +#include <common/RotationBufferProvider.h> + +namespace android { +namespace intel { + +class TngOverlayPlane : public OverlayPlaneBase { + +public: + TngOverlayPlane(int index, int disp); + virtual ~TngOverlayPlane(); + + virtual bool flip(void *ctx); + virtual bool reset(); + virtual void* getContext() const; + + virtual bool initialize(uint32_t bufferCount); + virtual void deinitialize(); + virtual bool rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper); +protected: + virtual bool setDataBuffer(BufferMapper& mapper); + virtual bool flush(uint32_t flags); + +protected: + struct intel_dc_plane_ctx mContext; + RotationBufferProvider *mRotationBufProvider; +}; + +} // namespace intel +} // namespace android + +#endif /* TNG_OVERLAY_PLANE_H */ diff --git a/merrifield/ips/tangier/TngPlaneManager.cpp b/merrifield/ips/tangier/TngPlaneManager.cpp new file mode 100644 index 0000000..d973aa9 --- /dev/null +++ b/merrifield/ips/tangier/TngPlaneManager.cpp @@ -0,0 +1,196 @@ +/* +// 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 <tangier/TngPlaneManager.h> +#include <tangier/TngPrimaryPlane.h> +#include <tangier/TngSpritePlane.h> +#include <tangier/TngOverlayPlane.h> +#include <tangier/TngCursorPlane.h> + +namespace android { +namespace intel { + +TngPlaneManager::TngPlaneManager() + : DisplayPlaneManager() +{ + memset(&mZorder, 0, sizeof(mZorder)); +} + +TngPlaneManager::~TngPlaneManager() +{ +} + +bool TngPlaneManager::initialize() +{ + mSpritePlaneCount = 1; // Sprite D + mOverlayPlaneCount = 2; // Overlay A & C + mPrimaryPlaneCount = 3; // Primary A, B, C + mCursorPlaneCount = 3; + + return DisplayPlaneManager::initialize(); +} + +void TngPlaneManager::deinitialize() +{ + DisplayPlaneManager::deinitialize(); +} + +DisplayPlane* TngPlaneManager::allocPlane(int index, int type) +{ + DisplayPlane *plane = 0; + + switch (type) { + case DisplayPlane::PLANE_PRIMARY: + plane = new TngPrimaryPlane(index, index); + break; + case DisplayPlane::PLANE_SPRITE: + plane = new TngSpritePlane(index, 0); + break; + case DisplayPlane::PLANE_OVERLAY: + plane = new TngOverlayPlane(index, 0); + break; + case DisplayPlane::PLANE_CURSOR: + plane = new TngCursorPlane(index, index /*disp */); + break; + default: + ETRACE("unsupported type %d", type); + break; + } + if (plane && !plane->initialize(DisplayPlane::MIN_DATA_BUFFER_COUNT)) { + ETRACE("failed to initialize plane."); + DEINIT_AND_DELETE_OBJ(plane); + } + + return plane; +} + +bool TngPlaneManager::isValidZOrder(int dsp, ZOrderConfig& config) +{ + // check whether it's a supported z order config + int firstRGB = -1; + int lastRGB = -1; + int firstOverlay = -1; + int lastOverlay = -1; + + for (int i = 0; i < (int)config.size(); i++) { + const ZOrderLayer *layer = config[i]; + switch (layer->planeType) { + case DisplayPlane::PLANE_PRIMARY: + case DisplayPlane::PLANE_SPRITE: + if (firstRGB == -1) { + firstRGB = i; + lastRGB = i; + } else { + lastRGB = i; + } + break; + case DisplayPlane::PLANE_OVERLAY: + case DisplayPlane::PLANE_CURSOR: + if (firstOverlay == -1) { + firstOverlay = i; + lastOverlay = i; + } else { + lastOverlay = i; + } + break; + } + } + + if ((lastRGB < firstOverlay) || (firstRGB > lastOverlay)) { + return true; + } else { + VTRACE("invalid z order config. rgb (%d, %d) yuv (%d, %d)", + firstRGB, lastRGB, firstOverlay, lastOverlay); + return false; + } +} + +bool TngPlaneManager::assignPlanes(int dsp, ZOrderConfig& config) +{ + // probe if plane is available + int size = (int)config.size(); + for (int i = 0; i < size; i++) { + const ZOrderLayer *layer = config.itemAt(i); + if (!getFreePlanes(dsp, layer->planeType)) { + DTRACE("no plane available for dsp %d, type %d", dsp, layer->planeType); + return false; + } + } + + if (config.size() == 1 && config[0]->planeType == DisplayPlane::PLANE_SPRITE) { + config[0]->planeType == DisplayPlane::PLANE_PRIMARY; + } + + // allocate planes + for (int i = 0; i < size; i++) { + ZOrderLayer *layer = config.itemAt(i); + layer->plane = getPlaneHelper(dsp, layer->planeType); + if (layer->plane == NULL) { + // should never happen!! + ETRACE("failed to assign plane for type %d", layer->planeType); + return false; + } + // sequence !!!!! enabling plane before setting zorder + // see TngSpritePlane::enablePlane implementation!!!! + layer->plane->enable(); + } + + // setup Z order + for (int i = 0; i < size; i++) { + ZOrderLayer *layer = config.itemAt(i); + layer->plane->setZOrderConfig(config, &mZorder); + } + + return true; +} + +void* TngPlaneManager::getZOrderConfig() const +{ + return (void*)&mZorder; +} + +DisplayPlane* TngPlaneManager::getPlaneHelper(int dsp, int type) +{ + RETURN_NULL_IF_NOT_INIT(); + + if (dsp < 0 || dsp > IDisplayDevice::DEVICE_EXTERNAL) { + ETRACE("Invalid display device %d", dsp); + return 0; + } + + int index = dsp == IDisplayDevice::DEVICE_PRIMARY ? 0 : 1; + + if (type == DisplayPlane::PLANE_PRIMARY || + type == DisplayPlane::PLANE_CURSOR) { + return getPlane(type, index); + } else if (type == DisplayPlane::PLANE_SPRITE) { + return getAnyPlane(type); + } else if (type == DisplayPlane::PLANE_OVERLAY) { + // use overlay A for pipe A and overlay C for pipe B if possible + DisplayPlane *plane = getPlane(type, index); + if (plane == NULL) { + plane = getPlane(type, !index); + } + return plane; + } else { + ETRACE("invalid plane type %d", type); + return 0; + } +} + +} // namespace intel +} // namespace android + diff --git a/merrifield/ips/tangier/TngPlaneManager.h b/merrifield/ips/tangier/TngPlaneManager.h new file mode 100644 index 0000000..e6717bb --- /dev/null +++ b/merrifield/ips/tangier/TngPlaneManager.h @@ -0,0 +1,50 @@ +/* +// 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. +*/ +#ifndef TNG_PLANE_MANAGER_H +#define TNG_PLANE_MANAGER_H + +#include <DisplayPlaneManager.h> +#include <linux/psb_drm.h> + +namespace android { +namespace intel { + +class TngPlaneManager : public DisplayPlaneManager { +public: + TngPlaneManager(); + virtual ~TngPlaneManager(); + +public: + virtual bool initialize(); + virtual void deinitialize(); + virtual bool isValidZOrder(int dsp, ZOrderConfig& config); + virtual bool assignPlanes(int dsp, ZOrderConfig& config); + // TODO: remove this API + virtual void* getZOrderConfig() const; + +protected: + DisplayPlane* allocPlane(int index, int type); + DisplayPlane* getPlaneHelper(int dsp, int type); + +private: + struct intel_dc_plane_zorder mZorder; +}; + +} // namespace intel +} // namespace android + + +#endif /* TNG_PLANE_MANAGER_H */ diff --git a/merrifield/ips/tangier/TngPrimaryPlane.cpp b/merrifield/ips/tangier/TngPrimaryPlane.cpp new file mode 100644 index 0000000..7d72f0f --- /dev/null +++ b/merrifield/ips/tangier/TngPrimaryPlane.cpp @@ -0,0 +1,167 @@ +/* +// 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 <Drm.h> +#include <tangier/TngPrimaryPlane.h> +#include <tangier/TngGrallocBuffer.h> +#include <common/PixelFormat.h> + +namespace android { +namespace intel { + +TngPrimaryPlane::TngPrimaryPlane(int index, int disp) + : TngSpritePlane(index, disp) +{ + CTRACE(); + mType = PLANE_PRIMARY; + mForceBottom = true; + mAbovePrimary = false; +} + +TngPrimaryPlane::~TngPrimaryPlane() +{ + CTRACE(); +} + +void TngPrimaryPlane::setFramebufferTarget(buffer_handle_t handle) +{ + CTRACE(); + + // do not need to update the buffer handle + if (mCurrentDataBuffer != handle) + mUpdateMasks |= PLANE_BUFFER_CHANGED; + else + mUpdateMasks &= ~PLANE_BUFFER_CHANGED; + + // if no update then do Not need set data buffer + if (!mUpdateMasks) + return; + + // don't need to map data buffer for primary plane + mContext.type = DC_PRIMARY_PLANE; + mContext.ctx.prim_ctx.update_mask = SPRITE_UPDATE_ALL; + mContext.ctx.prim_ctx.index = mIndex; + mContext.ctx.prim_ctx.pipe = mDevice; + mContext.ctx.prim_ctx.linoff = 0; + mContext.ctx.prim_ctx.stride = align_to((4 * align_to(mPosition.w, 32)), 64); + mContext.ctx.prim_ctx.pos = 0; + mContext.ctx.prim_ctx.size = + ((mPosition.h - 1) & 0xfff) << 16 | ((mPosition.w - 1) & 0xfff); + mContext.ctx.prim_ctx.surf = 0; + mContext.ctx.prim_ctx.contalpa = 0; + + mContext.ctx.prim_ctx.cntr = PixelFormat::PLANE_PIXEL_FORMAT_BGRA8888; + mContext.ctx.prim_ctx.cntr |= 0x80000000; + + mCurrentDataBuffer = handle; +} + +bool TngPrimaryPlane::enablePlane(bool enabled) +{ + RETURN_FALSE_IF_NOT_INIT(); + + struct drm_psb_register_rw_arg arg; + memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); + if (enabled) { + arg.plane_enable_mask = 1; + } else { + arg.plane_disable_mask = 1; + } + arg.plane.type = DC_PRIMARY_PLANE; + arg.plane.index = mIndex; + arg.plane.ctx = 0; + + // issue ioctl + Drm *drm = Hwcomposer::getInstance().getDrm(); + bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); + if (ret == false) { + WTRACE("primary enabling (%d) failed with error code %d", enabled, ret); + return false; + } + + return true; + +} + +bool TngPrimaryPlane::setDataBuffer(buffer_handle_t handle) +{ + if (!handle) { + setFramebufferTarget(handle); + return true; + } + + TngGrallocBuffer tmpBuf(handle); + uint32_t usage; + bool ret; + + ATRACE("handle = %#x", handle); + + usage = tmpBuf.getUsage(); + if (GRALLOC_USAGE_HW_FB & usage) { + setFramebufferTarget(handle); + return true; + } + + // use primary as a sprite + ret = DisplayPlane::setDataBuffer(handle); + if (ret == false) { + ETRACE("failed to set data buffer"); + return ret; + } + + mContext.type = DC_PRIMARY_PLANE; + return true; +} + +void TngPrimaryPlane::setZOrderConfig(ZOrderConfig& zorderConfig, + void *nativeConfig) +{ + if (!nativeConfig) { + ETRACE("Invalid parameter, no native config"); + return; + } + + mForceBottom = false; + + int primaryIndex = -1; + int overlayIndex = -1; + // only consider force bottom when overlay is active + for (size_t i = 0; i < zorderConfig.size(); i++) { + DisplayPlane *plane = zorderConfig[i]->plane; + if (plane->getType() == DisplayPlane::PLANE_PRIMARY) + primaryIndex = i; + if (plane->getType() == DisplayPlane::PLANE_OVERLAY) { + overlayIndex = i; + } + } + + // if has overlay plane which is below primary plane + if (overlayIndex > primaryIndex) { + mForceBottom = true; + } + + struct intel_dc_plane_zorder *zorder = + (struct intel_dc_plane_zorder *)nativeConfig; + zorder->forceBottom[mIndex] = mForceBottom ? 1 : 0; +} + +bool TngPrimaryPlane::assignToDevice(int disp) +{ + return true; +} + +} // namespace intel +} // namespace android diff --git a/merrifield/ips/tangier/TngPrimaryPlane.h b/merrifield/ips/tangier/TngPrimaryPlane.h new file mode 100644 index 0000000..22dbbd3 --- /dev/null +++ b/merrifield/ips/tangier/TngPrimaryPlane.h @@ -0,0 +1,40 @@ +/* +// 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. +*/ +#ifndef TNG_PRIMARY_PLANE_H +#define TNG_PRIMARY_PLANE_H + +#include <tangier/TngSpritePlane.h> + +namespace android { +namespace intel { + +class TngPrimaryPlane : public TngSpritePlane { +public: + TngPrimaryPlane(int index, int disp); + virtual ~TngPrimaryPlane(); +public: + bool setDataBuffer(buffer_handle_t handle); + void setZOrderConfig(ZOrderConfig& config, void *nativeConfig); + bool assignToDevice(int disp); +private: + void setFramebufferTarget(buffer_handle_t handle); + bool enablePlane(bool enabled); +}; + +} // namespace intel +} // namespace android + +#endif /* TNG_PRIMARY_PLANE_H */ diff --git a/merrifield/ips/tangier/TngSpritePlane.cpp b/merrifield/ips/tangier/TngSpritePlane.cpp new file mode 100644 index 0000000..c4e7e2c --- /dev/null +++ b/merrifield/ips/tangier/TngSpritePlane.cpp @@ -0,0 +1,215 @@ +/* +// 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 <Hwcomposer.h> +#include <BufferManager.h> +#include <tangier/TngSpritePlane.h> +#include <common/PixelFormat.h> + +namespace android { +namespace intel { + +TngSpritePlane::TngSpritePlane(int index, int disp) + : SpritePlaneBase(index, disp) +{ + CTRACE(); + memset(&mContext, 0, sizeof(mContext)); +} + +TngSpritePlane::~TngSpritePlane() +{ + CTRACE(); +} + +bool TngSpritePlane::setDataBuffer(BufferMapper& mapper) +{ + int bpp; + int srcX, srcY; + int dstX, dstY, dstW, dstH; + uint32_t spriteFormat; + uint32_t stride; + uint32_t linoff; + uint32_t planeAlpha; + + CTRACE(); + + // setup plane position + dstX = mPosition.x; + dstY = mPosition.y; + dstW = mPosition.w; + dstH = mPosition.h; + + checkPosition(dstX, dstY, dstW, dstH); + + // setup plane format + if (!PixelFormat::convertFormat(mapper.getFormat(), spriteFormat, bpp)) { + ETRACE("unsupported format %#x", mapper.getFormat()); + return false; + } + + // setup stride and source buffer crop + srcX = mapper.getCrop().x; + srcY = mapper.getCrop().y; + stride = mapper.getStride().rgb.stride; + linoff = srcY * stride + srcX * bpp; + + // setup plane alpha + if ((mBlending == HWC_BLENDING_PREMULT) && (mPlaneAlpha == 0)) { + planeAlpha = mPlaneAlpha | 0x80000000; + } else { + // disable plane alpha to offload HW + planeAlpha = 0; + } + + // unlikely happen, but still we need make sure linoff is valid + if (linoff > (stride * mapper.getHeight())) { + ETRACE("invalid source crop"); + return false; + } + + // update context + mContext.type = DC_SPRITE_PLANE; + mContext.ctx.sp_ctx.index = mIndex; + mContext.ctx.sp_ctx.pipe = mDevice; + // none blending and BRGA format layer,set format to BGRX8888 + if (mBlending == HWC_BLENDING_NONE && spriteFormat == PixelFormat::PLANE_PIXEL_FORMAT_BGRA8888) + mContext.ctx.sp_ctx.cntr = PixelFormat::PLANE_PIXEL_FORMAT_BGRX8888 + | 0x80000000; + else + mContext.ctx.sp_ctx.cntr = spriteFormat | 0x80000000; + mContext.ctx.sp_ctx.linoff = linoff; + mContext.ctx.sp_ctx.stride = stride; + mContext.ctx.sp_ctx.surf = mapper.getGttOffsetInPage(0) << 12; + mContext.ctx.sp_ctx.pos = (dstY & 0xfff) << 16 | (dstX & 0xfff); + mContext.ctx.sp_ctx.size = + ((dstH - 1) & 0xfff) << 16 | ((dstW - 1) & 0xfff); + mContext.ctx.sp_ctx.contalpa = planeAlpha; + mContext.ctx.sp_ctx.update_mask = SPRITE_UPDATE_ALL; + mContext.gtt_key = (uint64_t)mapper.getCpuAddress(0); + + VTRACE("cntr = %#x, linoff = %#x, stride = %#x," + "surf = %#x, pos = %#x, size = %#x, contalpa = %#x", + mContext.ctx.sp_ctx.cntr, + mContext.ctx.sp_ctx.linoff, + mContext.ctx.sp_ctx.stride, + mContext.ctx.sp_ctx.surf, + mContext.ctx.sp_ctx.pos, + mContext.ctx.sp_ctx.size, + mContext.ctx.sp_ctx.contalpa); + return true; +} + +void* TngSpritePlane::getContext() const +{ + CTRACE(); + return (void *)&mContext; +} + +bool TngSpritePlane::enablePlane(bool enabled) +{ + RETURN_FALSE_IF_NOT_INIT(); + + struct drm_psb_register_rw_arg arg; + memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); + if (enabled) { + arg.plane_enable_mask = 1; + } else { + arg.plane_disable_mask = 1; + } + arg.plane.type = DC_SPRITE_PLANE; + arg.plane.index = mIndex; + arg.plane.ctx = 0; + + // issue ioctl + Drm *drm = Hwcomposer::getInstance().getDrm(); + bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); + if (ret == false) { + WTRACE("sprite enabling (%d) failed with error code %d", enabled, ret); + return false; + } + + Hwcomposer& hwc = Hwcomposer::getInstance(); + DisplayPlaneManager *pm = hwc.getPlaneManager(); + void *config = pm->getZOrderConfig(); + if (config != NULL) { + struct intel_dc_plane_zorder *zorder = (struct intel_dc_plane_zorder *)config; + zorder->abovePrimary = 0; + } + + return true; + +} + +bool TngSpritePlane::isDisabled() +{ + RETURN_FALSE_IF_NOT_INIT(); + + struct drm_psb_register_rw_arg arg; + memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); + + if (mType == DisplayPlane::PLANE_SPRITE) + arg.plane.type = DC_SPRITE_PLANE; + else + arg.plane.type = DC_PRIMARY_PLANE; + + arg.get_plane_state_mask = 1; + arg.plane.index = mIndex; + arg.plane.ctx = 0; + + // issue ioctl + Drm *drm = Hwcomposer::getInstance().getDrm(); + bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); + if (ret == false) { + WTRACE("plane state query failed with error code %d", ret); + return false; + } + + return arg.plane.ctx == PSB_DC_PLANE_DISABLED; +} + +void TngSpritePlane::setZOrderConfig(ZOrderConfig& zorderConfig, + void *nativeConfig) +{ + if (!nativeConfig) { + ETRACE("Invalid parameter, no native config"); + return; + } + + mAbovePrimary = false; + + int primaryIndex = -1; + int spriteIndex = -1; + // only consider force bottom when overlay is active + for (size_t i = 0; i < zorderConfig.size(); i++) { + DisplayPlane *plane = zorderConfig[i]->plane; + if (plane->getType() == DisplayPlane::PLANE_PRIMARY) + primaryIndex = i; + if (plane->getType() == DisplayPlane::PLANE_SPRITE) { + spriteIndex = i; + } + } + + // if has overlay plane which is below primary plane + if (spriteIndex > primaryIndex) { + mAbovePrimary = true; + } + + struct intel_dc_plane_zorder *zorder = + (struct intel_dc_plane_zorder *)nativeConfig; + zorder->abovePrimary = mAbovePrimary ? 1 : 0; +} +} // namespace intel +} // namespace android diff --git a/merrifield/ips/tangier/TngSpritePlane.h b/merrifield/ips/tangier/TngSpritePlane.h new file mode 100644 index 0000000..1c6bcdc --- /dev/null +++ b/merrifield/ips/tangier/TngSpritePlane.h @@ -0,0 +1,48 @@ +/* +// 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. +*/ +#ifndef TNG_SPRITE_PLANE_H +#define TNG_SPRITE_PLANE_H + +#include <utils/KeyedVector.h> +#include <hal_public.h> +#include <Hwcomposer.h> +#include <BufferCache.h> +#include <DisplayPlane.h> + +#include <common/SpritePlaneBase.h> + +namespace android { +namespace intel { + +class TngSpritePlane : public SpritePlaneBase { +public: + TngSpritePlane(int index, int disp); + virtual ~TngSpritePlane(); +public: + virtual void* getContext() const; + virtual void setZOrderConfig(ZOrderConfig& config, void *nativeConfig); + virtual bool isDisabled(); +protected: + virtual bool setDataBuffer(BufferMapper& mapper); + virtual bool enablePlane(bool enabled); +protected: + struct intel_dc_plane_ctx mContext; +}; + +} // namespace intel +} // namespace android + +#endif /* TNG_SPRITE_PLANE_H */ |