/*
// 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;
#ifdef ENABLE_ROTATION_180
linoff = (mapper.getCrop().h + srcY - 1) * stride + (srcX + mapper.getCrop().w - 1) * bpp;
#else
linoff = srcY * stride + srcX * bpp;
#endif
// 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);
#ifdef ENABLE_ROTATION_180
mContext.ctx.sp_ctx.cntr |= 1 << 15;
#endif
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