/* // 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 #include #include #include #include #include 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); } bool AnnRGBPlane::reset() { while (!mScalingBufferMap.isEmpty()) { uint32_t handle = mScalingBufferMap.valueAt(0); Hwcomposer::getInstance().getBufferManager()->freeGrallocBuffer(handle); mScalingBufferMap.removeItemsAt(0); } return DisplayPlane::reset(); } bool AnnRGBPlane::flip(void*) { if (mForceScaling) { BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); if (!bm->blitGrallocBuffer(mScalingSource, mScalingTarget, mDisplayCrop, 0)) { ELOGTRACE("Failed to blit RGB buffer."); return false; } } return true; } void* AnnRGBPlane::getContext() const { CTRACE(); return (void *)&mContext; } void AnnRGBPlane::setZOrderConfig(ZOrderConfig& /* config */, void * /* nativeConfig */) { CTRACE(); } bool AnnRGBPlane::setDataBuffer(uint32_t handle) { if (!handle) { if (!mForceScaling) { setFramebufferTarget(handle); return true; } else { ELOGTRACE("Invalid handle while scaling is required."); return false; } } if (mForceScaling) { BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); ssize_t index = mScalingBufferMap.indexOfKey(handle); if (index < 0) { mScalingTarget = bm->allocGrallocBuffer( mDisplayWidth, mDisplayHeight, HAL_PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE); if (!mScalingTarget) { ELOGTRACE("Failed to allocate gralloc buffer."); return false; } if (mScalingBufferMap.size() >= MAX_SCALING_BUF_COUNT) { while (!mScalingBufferMap.isEmpty()) { uint32_t handle = mScalingBufferMap.valueAt(0); bm->freeGrallocBuffer(handle); mScalingBufferMap.removeItemsAt(0); } } mScalingBufferMap.add(handle, mScalingTarget); } else { mScalingTarget = mScalingBufferMap.valueAt(index); } mScalingSource = handle; handle = mScalingTarget; } TngGrallocBuffer tmpBuf(handle); uint32_t usage; bool ret; ALOGTRACE("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) { ELOGTRACE("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)) { ELOGTRACE("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())) { ELOGTRACE("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; 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; VLOGTRACE("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) { WLOGTRACE("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) { WLOGTRACE("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(uint32_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); VLOGTRACE("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