1
0
Fork 0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

847 lines
28 KiB

/*
*
* Copyright 2010 Rockchip Electronics S.LSI Co. LTD
*
* 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.
*/
/*
* File:
* ppOp.h
* Description:
* Global struct definition in VPU module
* Author:
* Wu JunMin
* Date:
* 2015-03-31 14:43:40
*/
#define LOG_TAG "PpOp"
#define ATRACE_TAG ATRACE_TAG_VIDEO
#include <utils/Log.h>
#ifndef AVS40
#include <utils/Trace.h>
#endif
#include "vpu.h"
#include "vpu_mem.h"
#include "ppOp.h"
#include "reg.h"
#include <stdlib.h>
#ifdef AVS40
#undef ALOGV
#define ALOGV LOGV
#undef ALOGD
#define ALOGD LOGD
#undef ALOGI
#define ALOGI LOGI
#undef ALOGW
#define ALOGW LOGW
#undef ALOGE
#define ALOGE LOGE
#endif
namespace android {
#define PPOP_DEBUG 0
class VPUReg {
public:
VPUReg(VPU_CLIENT_TYPE type);
~VPUReg();
void SetRegisterFile(RK_U32 id, RK_U32 value);
RK_U32 GetRegisterFile(RK_U32 id);
RK_U32 *addr() {return ptr;};
private:
VPU_CLIENT_TYPE vpuType;
RK_U32 size;
RK_U32 *ptr;
RK_U32 *start;
};
VPUReg::VPUReg(VPU_CLIENT_TYPE type)
: vpuType(VPU_TYPE_BUTT), ptr(NULL), start(NULL)
{
switch (type) {
case VPU_ENC : {
size = sizeof(RK_U32) * VPU_REG_NUM_ENC;
ptr = (RK_U32 *)malloc(size);
} break;
case VPU_DEC : {
size = sizeof(RK_U32) * VPU_REG_NUM_DEC;
ptr = (RK_U32 *)malloc(size);
} break;
case VPU_PP : {
size = sizeof(RK_U32) * VPU_REG_NUM_PP;
ptr = (RK_U32 *)malloc(size);
} break;
case VPU_DEC_PP : {
size = sizeof(RK_U32) * VPU_REG_NUM_DEC_PP;
ptr = (RK_U32 *)malloc(size);
} break;
default : {
ALOGE("invalid vpu client type: %d", type);
} break;
}
if (NULL != ptr) {
vpuType = type;
if (VPU_PP == vpuType) {
start = ptr;
} else {
start = ptr + VPU_REG_NUM_PP;
}
memset(ptr, 0, size);
} else {
ALOGE("failed to malloc resource for VPUReg");
size = 0;
}
}
typedef struct {
uint32_t srcAddr; // 16 align
uint32_t srcFormat;
uint32_t srcWidth; // 16 align max 2048
uint32_t srcHeight; // 16 align max 2048
uint32_t srcHStride; // 16 align max 2048
uint32_t srcVStride; // 16 align max 2048
uint32_t srcCrop8R; // crop rigth
uint32_t srcCrop8D; // crop down
uint32_t srcX; // src x
uint32_t srcY; // src y
uint32_t srcReserv[2];
uint32_t dstAddr; // 16 align
uint32_t dstFormat;
uint32_t dstWidth; // 16 align max 2048
uint32_t dstHeight; // 16 align max 2048
uint32_t dstHStride; // 16 align max 2048
uint32_t dstVStride; // 16 align max 2048
uint32_t dstReserv[2];
uint32_t dstX; // dst x
uint32_t dstY; // dst y
uint32_t vpuFd;
uint32_t rotation; // rotation angel
uint32_t yuvFullRange; // yuv is full range or not, set yuv trans table
uint32_t deinterlace; // do deinterlace or not
uint32_t optReserv[9];
uint32_t updated; // update flag
VPUReg *reg; // register set
uint32_t *checkSum;
} PP_INTERNAL;
VPUReg::~VPUReg()
{
vpuType = VPU_TYPE_BUTT;
if (NULL != ptr) {
free(ptr);
}
ptr = NULL;
start = NULL;
}
static const RK_U32 regMask[33] = { 0x00000000,
0x00000001, 0x00000003, 0x00000007, 0x0000000F,
0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
};
/* { SWREG, BITS, POSITION } */
static RK_U32 hwDecRegSpec[HWIF_LAST_REG + 1][3] = {
/* include script-generated part */
#include "vpuhwtable.h"
/* HWIF_DEC_IRQ_STAT */ {1, 7, 12},
/* HWIF_PP_IRQ_STAT */ {60, 2, 12},
/* dummy entry */ { 0, 0, 0}
};
void VPUReg::SetRegisterFile(RK_U32 id, RK_U32 value)
{
if (vpuType >= VPU_TYPE_BUTT) {
ALOGE("failed to SetRegisterFile to invalid VPUReg");
return ;
}
RK_U32 tmp = start[hwDecRegSpec[id][0]];
tmp &= ~(regMask[hwDecRegSpec[id][1]] << hwDecRegSpec[id][2]);
tmp |= (value & regMask[hwDecRegSpec[id][1]]) << hwDecRegSpec[id][2];
start[hwDecRegSpec[id][0]] = tmp;
}
RK_U32 VPUReg::GetRegisterFile(RK_U32 id)
{
if (vpuType >= VPU_TYPE_BUTT) {
ALOGE("failed to GetRegisterFile from invalid VPUReg");
return 0;
}
RK_U32 tmp = start[hwDecRegSpec[id][0]];
tmp = tmp >> hwDecRegSpec[id][2];
tmp &= regMask[hwDecRegSpec[id][1]];
return (tmp);
}
#define SetPpRegister(reg, id, value) do {reg->SetRegisterFile(id, value);} while (0)
static status_t ppSetSrcFormat(VPUReg *reg, uint32_t srcFormat)
{
switch (srcFormat) {
case PP_IN_FORMAT_YUV422INTERLAVE:
SetPpRegister(reg, HWIF_PP_IN_FORMAT, 0);
break;
case PP_IN_FORMAT_YUV420SEMI:
SetPpRegister(reg, HWIF_PP_IN_FORMAT, 1);
break;
case PP_IN_FORMAT_YUV420PLANAR:
SetPpRegister(reg, HWIF_PP_IN_FORMAT, 2);
break;
case PP_IN_FORMAT_YUV400:
SetPpRegister(reg, HWIF_PP_IN_FORMAT, 3);
break;
case PP_IN_FORMAT_YUV422SEMI:
SetPpRegister(reg, HWIF_PP_IN_FORMAT, 4);
break;
case PP_IN_FORMAT_YUV420SEMITIELED:
SetPpRegister(reg, HWIF_PP_IN_FORMAT, 5);
break;
case PP_IN_FORMAT_YUV440SEMI:
SetPpRegister(reg, HWIF_PP_IN_FORMAT, 6);
break;
case PP_IN_FORMAT_YUV444_SEMI:
SetPpRegister(reg, HWIF_PP_IN_FORMAT, 7);
SetPpRegister(reg, HWIF_PP_IN_FORMAT_ES, 0);
break;
case PP_IN_FORMAT_YUV411_SEMI:
SetPpRegister(reg, HWIF_PP_IN_FORMAT, 7);
SetPpRegister(reg, HWIF_PP_IN_FORMAT_ES, 1);
break;
default:
return BAD_VALUE;
}
return OK;
}
status_t ppSetDstFormat(VPUReg *reg, uint32_t dstFormat)
{
switch (dstFormat) {
case PP_OUT_FORMAT_RGB565:
SetPpRegister(reg, HWIF_R_MASK, 0xF800F800);
SetPpRegister(reg, HWIF_G_MASK, 0x07E007E0);
SetPpRegister(reg, HWIF_B_MASK, 0x001F001F);
SetPpRegister(reg, HWIF_RGB_R_PADD, 0);
SetPpRegister(reg, HWIF_RGB_G_PADD, 5);
SetPpRegister(reg, HWIF_RGB_B_PADD, 11);
SetPpRegister(reg, HWIF_DITHER_SELECT_R, 2);
SetPpRegister(reg, HWIF_DITHER_SELECT_G, 3);
SetPpRegister(reg, HWIF_DITHER_SELECT_B, 2);
SetPpRegister(reg, HWIF_RGB_PIX_IN32, 1);
SetPpRegister(reg, HWIF_PP_OUT_SWAP16_E,1);
SetPpRegister(reg, HWIF_PP_OUT_FORMAT, 0);
break;
case PP_OUT_FORMAT_ARGB:
SetPpRegister(reg, HWIF_R_MASK, 0x000000FF | (0xff << 24));
SetPpRegister(reg, HWIF_G_MASK, 0x0000FF00 | (0xff << 24));
SetPpRegister(reg, HWIF_B_MASK, 0x00FF0000 | (0xff << 24));
SetPpRegister(reg, HWIF_RGB_R_PADD, 24);
SetPpRegister(reg, HWIF_RGB_G_PADD, 16);
SetPpRegister(reg, HWIF_RGB_B_PADD, 8);
SetPpRegister(reg, HWIF_RGB_PIX_IN32, 0);
SetPpRegister(reg, HWIF_PP_OUT_FORMAT, 0);
break;
case PP_OUT_FORMAT_ABGR:
SetPpRegister(reg, HWIF_B_MASK, 0x000000FF | (0xff << 24));
SetPpRegister(reg, HWIF_G_MASK, 0x0000FF00 | (0xff << 24));
SetPpRegister(reg, HWIF_R_MASK, 0x00FF0000 | (0xff << 24));
SetPpRegister(reg, HWIF_RGB_B_PADD, 24);
SetPpRegister(reg, HWIF_RGB_G_PADD, 16);
SetPpRegister(reg, HWIF_RGB_R_PADD, 8);
SetPpRegister(reg, HWIF_RGB_PIX_IN32, 0);
SetPpRegister(reg, HWIF_PP_OUT_FORMAT, 0);
break;
case PP_OUT_FORMAT_YUV422INTERLAVE:
SetPpRegister(reg, HWIF_PP_OUT_FORMAT, 3);
break;
case PP_OUT_FORMAT_YUV420INTERLAVE:
SetPpRegister(reg, HWIF_PP_OUT_CH_BASE, 0);
SetPpRegister(reg, HWIF_PP_OUT_FORMAT, 5);
break;
default:
return BAD_VALUE;
}
return OK;
}
status_t ppOpUpdate(PP_INTERNAL *hnd)
{
PP_INTERNAL *p = hnd;
VPUReg *reg = p->reg;
int srcwid_alig16;
int srchei_alig16;
if ( p->optReserv[0] )
{
p->srcWidth = p->srcWidth&(~15);
p->srcHeight = p->srcHeight&(~15);
}
srcwid_alig16 = (p->srcWidth+15)&(~15);
srchei_alig16 = (p->srcHeight+15)&(~15);
if (p->updated) {
//get srcCrop para
if(srcwid_alig16 != p->srcWidth)
p->srcCrop8R = 1;
else
p->srcCrop8R = 0;
if(srchei_alig16 != p->srcHeight)
p->srcCrop8D= 1;
else
p->srcCrop8D= 0;
//update dstX and dstWid
p->dstWidth = (p->dstWidth + (p->dstX&7) + 7)&(~7);
p->dstX = p->dstX&(~7);
SetPpRegister(reg, HWIF_PP_AXI_RD_ID, 0xFF);//0xFF);
SetPpRegister(reg, HWIF_PP_AXI_WR_ID, 0xFF);//0xFF);
SetPpRegister(reg, HWIF_PP_AHB_HLOCK_E, 1);
SetPpRegister(reg, HWIF_PP_SCMD_DIS, 1);
SetPpRegister(reg, HWIF_PP_IN_A2_ENDSEL, 1);
SetPpRegister(reg, HWIF_PP_IN_A1_SWAP32, 1);
SetPpRegister(reg, HWIF_PP_IN_A1_ENDIAN, 1);
SetPpRegister(reg, HWIF_PP_IN_SWAP32_E, 1);
SetPpRegister(reg, HWIF_PP_DATA_DISC_E, 1);
SetPpRegister(reg, HWIF_PP_CLK_GATE_E, 1);
SetPpRegister(reg, HWIF_PP_IN_ENDIAN, 1);
SetPpRegister(reg, HWIF_PP_OUT_ENDIAN, 1);
SetPpRegister(reg, HWIF_PP_OUT_SWAP32_E, 1);
SetPpRegister(reg, HWIF_PP_MAX_BURST, 16);
SetPpRegister(reg, HWIF_EXT_ORIG_WIDTH, p->srcHStride>>4);
SetPpRegister(reg, HWIF_PP_IN_W_EXT, (((srcwid_alig16 / 16) & 0xE00) >> 9));
SetPpRegister(reg, HWIF_PP_IN_WIDTH, ((srcwid_alig16 / 16) & 0x1FF));
SetPpRegister(reg, HWIF_PP_IN_H_EXT, (((srchei_alig16 / 16) & 0x700) >> 8));
SetPpRegister(reg, HWIF_PP_IN_HEIGHT, ((srchei_alig16 / 16) & 0x0FF));
SetPpRegister(reg, HWIF_DISPLAY_WIDTH, p->dstHStride);
SetPpRegister(reg, HWIF_PP_OUT_WIDTH, p->dstWidth);
SetPpRegister(reg, HWIF_PP_OUT_HEIGHT, p->dstHeight);
SetPpRegister(reg, HWIF_PP_IN_STRUCT, p->deinterlace?3:0);
SetPpRegister(reg, HWIF_DEINT_E, p->deinterlace);
SetPpRegister(reg, HWIF_ROTATION_MODE, p->rotation);
SetPpRegister(reg, HWIF_DEINT_BLEND_E, 0);
SetPpRegister(reg, HWIF_DEINT_THRESHOLD, 256);
SetPpRegister(reg, HWIF_DEINT_EDGE_DET, 256);
SetPpRegister(reg, HWIF_RANGEMAP_COEF_Y, 9);
SetPpRegister(reg, HWIF_RANGEMAP_COEF_C, 9);
/*{
uint32_t srcY = p->srcAddr;
uint32_t srcCB = srcY + p->srcHStride * p->srcVStride;
uint32_t srcCR = srcCB + p->srcWidth * p->srcHeight / 4;
uint32_t bottomBusLuma = srcY + p->srcHStride;
uint32_t bottomBusChroma = srcCB + p->srcHStride;
SetPpRegister(reg, HWIF_PP_IN_LU_BASE, srcY);
SetPpRegister(reg, HWIF_PP_IN_CB_BASE, srcCB);
SetPpRegister(reg, HWIF_PP_IN_CR_BASE, srcCR);
SetPpRegister(reg, HWIF_PP_BOT_YIN_BASE, bottomBusLuma);
SetPpRegister(reg, HWIF_PP_BOT_CIN_BASE, bottomBusChroma);
SetPpRegister(reg, HWIF_PP_OUT_LU_BASE, p->dstAddr);
SetPpRegister(reg, HWIF_PP_OUT_CH_BASE, p->dstAddr + p->dstHStride * p->dstVStride);
}*/
{
uint32_t srcY;
uint32_t srcCB;
uint32_t srcCR;
uint32_t bottomBusLuma;
uint32_t bottomBusChroma;
uint32_t dstLum;
uint32_t dstChr;
if (!VPUMemJudgeIommu()) {
srcY = p->srcAddr + (p->srcX + p->srcY * p->srcHStride);
srcCB = srcY + p->srcHStride * p->srcVStride;
srcCR = srcCB + p->srcHStride * p->srcVStride / 4;
bottomBusLuma = srcY + p->srcHStride;
bottomBusChroma = srcCB + p->srcHStride;
dstLum = p->dstAddr + (p->dstX + p->dstY * p->dstHStride);
dstChr = p->dstAddr + p->dstHStride * p->dstVStride + (p->dstX + p->dstY * p->dstHStride / 2);
} else {
srcY = p->srcAddr | ((p->srcX + p->srcY * p->srcHStride)<<10);
srcCB = srcY + ((p->srcHStride * p->srcVStride)<<10);
srcCR = srcCB + ((p->srcHStride * p->srcVStride / 4)<<10);
bottomBusLuma = srcY + (p->srcHStride << 10);
bottomBusChroma = srcCB + (p->srcHStride << 10);
dstLum = p->dstAddr | ((p->dstX + p->dstY * p->dstHStride)<<10);
dstChr = p->dstAddr | ((p->dstHStride * p->dstVStride + (p->dstX + p->dstY * p->dstHStride / 2))<<10);
}
SetPpRegister(reg, HWIF_PP_IN_LU_BASE, srcY);
SetPpRegister(reg, HWIF_PP_IN_CB_BASE, srcCB);
SetPpRegister(reg, HWIF_PP_IN_CR_BASE, srcCR);
SetPpRegister(reg, HWIF_PP_BOT_YIN_BASE, bottomBusLuma);
SetPpRegister(reg, HWIF_PP_BOT_CIN_BASE, bottomBusChroma);
SetPpRegister(reg, HWIF_PP_OUT_LU_BASE, dstLum);
SetPpRegister(reg, HWIF_PP_OUT_CH_BASE, dstChr);
}
{
unsigned int inw,inh;
unsigned int outw,outh;
if(p->rotation == PP_ROTATION_RIGHT_90 || p->rotation == PP_ROTATION_LEFT_90)
{
outw = p->dstWidth - 1;//outWidth -1;
outh = p->dstHeight - 1;//outHeight -1;
inw = p->srcHeight - 1;//inWidth -1;
inh = p->srcWidth -1;//p->srcHeight - 1;//inHeigth -1;
}else
{
outw = p->dstWidth - 1;//outWidth -1;
outh = p->dstHeight - 1;//outHeight -1;
inw = p->srcWidth - 1;//inWidth -1;
inh = p->srcHeight -1;//p->srcHeight - 1;//inHeigth -1;
}
if(outh > inh && p->srcCrop8D)
{
inh = inh&(~15);
}
if(outw > inw && p->srcCrop8R)
{
inw = inw&(~15);
}
#if PPOP_DEBUG
ALOGD("p->rotation=%d, outw=%d, outh=%d, p->srcCrop8D=%d, p->srcCrop8R=%d\n", p->rotation, outw, outh, p->srcCrop8D, p->srcCrop8R);
#endif
SetPpRegister(reg, HWIF_PP_CROP8_R_E, p->srcCrop8R);
SetPpRegister(reg, HWIF_PP_CROP8_D_E, p->srcCrop8D);
if (inw < outw)
{
SetPpRegister(reg, HWIF_HOR_SCALE_MODE, 1);
SetPpRegister(reg, HWIF_SCALE_WRATIO, (outw<<16)/inw);
SetPpRegister(reg, HWIF_WSCALE_INVRA, (inw<<16)/outw);
}
else if (inw > outw)
{
SetPpRegister(reg, HWIF_HOR_SCALE_MODE, 2);
SetPpRegister(reg, HWIF_WSCALE_INVRA, ((outw+1)<<16)/(inw+1));
}
else
SetPpRegister(reg, HWIF_HOR_SCALE_MODE, 0);
if (inh < outh)
{
SetPpRegister(reg, HWIF_VER_SCALE_MODE, 1);
SetPpRegister(reg, HWIF_SCALE_HRATIO, (outh<<16)/inh);
SetPpRegister(reg, HWIF_HSCALE_INVRA, (inh<<16)/outh);
}
else if (inh > outh)
{
SetPpRegister(reg, HWIF_VER_SCALE_MODE, 2);
SetPpRegister(reg, HWIF_HSCALE_INVRA, ((outh+1)<<16)/(inh+1)+1);
}
else
SetPpRegister(reg, HWIF_VER_SCALE_MODE, 0);
}
}
SetPpRegister(reg, HWIF_PP_E, 1);
return OK;
}
status_t ppOpInit(PP_OP_HANDLE *hnd, PP_OPERATION *init)
{
if (NULL == hnd || NULL == init) {
ALOGE("invalid arg reg: %p init: %p", hnd, init);
return BAD_VALUE;
}
VPUReg *reg = new VPUReg(VPU_PP);
PP_INTERNAL *p = (PP_INTERNAL *)malloc(sizeof(PP_INTERNAL));
if (NULL == p || NULL == reg) {
ALOGE("can not malloc resource for pp operation");
if (p) free(p);
if (reg) delete(reg);
return NO_MEMORY;
}
memcpy(p, init, sizeof(PP_INTERNAL));
#if PPOP_DEBUG
ALOGI("src: vw %d, vh %d, w: %d h %d x %d, y %d, format %d, addr 0x%x", init->srcHStride, init->srcVStride, init->srcWidth, init->srcHeight, init->srcX, init->srcY, init->srcFormat, init->srcAddr);
ALOGI("dst: vw %d, vh %d, w: %d h %d x %d, y %d, format %d, addr 0x%x", init->dstHStride, init->dstVStride, init->dstWidth, init->dstHeight, init->dstX, init->dstY, init->dstFormat, init->dstAddr);
#endif
if (ppSetSrcFormat(reg, init->srcFormat) || ppSetDstFormat(reg, init->dstFormat)) {
ALOGE("invalid format src: %d, dst %d", init->srcFormat, init->dstFormat);
if (p) free(p);
if (reg) free(reg);
return BAD_VALUE;
}
{
unsigned int inw,inh;
unsigned int outw,outh;
if(init->rotation == PP_ROTATION_RIGHT_90 || init->rotation == PP_ROTATION_LEFT_90)
{
outw = init->dstWidth - 1;//outWidth -1;
outh = init->dstHeight - 1;//outHeight -1;
inw = init->srcHeight - 1;//inWidth -1;
inh = init->srcWidth -1;//p->srcHeight - 1;//inHeigth -1;
}else
{
outw = init->dstWidth - 1;//outWidth -1;
outh = init->dstHeight - 1;//outHeight -1;
inw = init->srcWidth - 1;//inWidth -1;
inh = init->srcHeight -1;//p->srcHeight - 1;//inHeigth -1;
}
if((outw > inw && outh < inh) || (outw < inw && outh > inh))
{
ALOGD("PP operat error width and height scale mode is different!");
return BAD_VALUE;
}
if((outw > 3*inw) || (outh > 3*(inh-2)))
{
ALOGD("PP operat error because scale rate more than 3x!");
return BAD_VALUE;
}
if( outw > inw && outh > inh)
p->optReserv[0] = 1;
else
p->optReserv[0] = 0;
}
//ALOGI("ppSetSrcFormat");
p->updated = 1;
p->reg = reg;
p->checkSum = (uint32_t*)p;
*hnd = (PP_OP_HANDLE)p;
ppOpUpdate(p);
return OK;
}
static status_t ppOptCheck(PP_SET_OPT opt)
{
status_t ret = BAD_VALUE;
switch (opt) {
case PP_SET_SRC_ADDR:
case PP_SET_SRC_FORMAT:
case PP_SET_SRC_WIDTH:
case PP_SET_SRC_HEIGHT:
case PP_SET_SRC_HSTRIDE:
case PP_SET_SRC_VSTRIDE:
case PP_SET_DST_ADDR:
case PP_SET_DST_FORMAT:
case PP_SET_DST_WIDTH:
case PP_SET_DST_HEIGHT:
case PP_SET_DST_HSTRIDE:
case PP_SET_DST_VSTRIDE:
case PP_SET_ROTATION:
case PP_SET_YUV_RANGE:
case PP_SET_DEINTERLACE:
case PP_SET_VPU_FD: {
ret = OK;
} break;
default : {
} break;
}
return ret;
}
status_t ppOpSet(PP_OP_HANDLE hnd, PP_SET_OPT opt, uint32_t val)
{
if (NULL == hnd || ppOptCheck(opt)) {
ALOGE("invalid arg hnd: %p opt: %d", hnd, opt);
return BAD_VALUE;
}
if (((uint32_t *)hnd)[opt] != val) {
((uint32_t *)hnd)[opt] = val;
((PP_INTERNAL *)hnd)->updated = 1;
}
return OK;
}
static status_t ppHnadleCheck(PP_INTERNAL *p)
{
if (NULL == p) {
ALOGE("invalid NULL hnd");
return BAD_VALUE;
}
if (p->checkSum != (uint32_t*)p) {
ALOGE("invalid hnd: %p checkSum 0x%.8x", p, p->checkSum);
return BAD_VALUE;
}
if (p->vpuFd <= 0) {
ALOGE("invalid vpu client handle: %d", p->vpuFd);
return BAD_VALUE;
}
if (NULL == p->reg) {
ALOGE("invalid register set: %p", p->reg);
return BAD_VALUE;
}
return OK;
}
status_t ppOpPerform(PP_OP_HANDLE hnd)
{
PP_INTERNAL *p = (PP_INTERNAL *)hnd;
status_t ret = ppHnadleCheck(p);
if (ret) return ret;
ppOpUpdate(p);
#if PPOP_DEBUG
RK_U32 *ptr = p->reg->addr();
for (int i=0; i < VPU_REG_NUM_PP; i++) {
ALOGE("send reg[%.2d] val: 0x%.8x", i, ptr[i]);
}
#endif
{
RK_U32 *ptr = p->reg->addr();
printf("send reg[41] val: 0x%.8x\n", ptr[41]);
}
return VPUClientSendReg(p->vpuFd, p->reg->addr(), VPU_REG_NUM_PP);//VPU_REG_NUM_PP);
}
status_t ppOpSync(PP_OP_HANDLE hnd)
{
PP_INTERNAL *p = (PP_INTERNAL *)hnd;
status_t ret = ppHnadleCheck(p);
if (ret) return ret;
VPU_CMD_TYPE cmd;
RK_S32 len;
ret = VPUClientWaitResult(p->vpuFd, p->reg->addr(), VPU_REG_NUM_PP, &cmd, &len);
#if PPOP_DEBUG
RK_U32 *ptr = p->reg->addr();
for (int i=0; i < VPU_REG_NUM_PP; i++) {
ALOGE("recv reg[%.2d] val: 0x%.8x", i, ptr[i]);
}
#endif
if (ret) return ret;
if (cmd != VPU_SEND_CONFIG_ACK_OK) return BAD_VALUE;
return OK;
}
status_t ppOpRelease(PP_OP_HANDLE hnd)
{
PP_INTERNAL *p = (PP_INTERNAL *)hnd;
status_t ret = ppHnadleCheck(p);
if (ret) return ret;
if (p->reg) delete(p->reg);
free(p);
return OK;
}
}
#if BUILD_PPOP_TEST
#define SRC_WIDTH (1920)//(1920)
#define SRC_HEIGHT (1080)//(1080)
#define SRC_SIZE (SRC_WIDTH*SRC_HEIGHT*2)
#define DST_WIDTH (720)//(720)
#define DST_HEIGHT (1280)
#define DST_SIZE (DST_WIDTH*DST_HEIGHT*2)
#include "vpu_mem.h"
#include "vpu.h"
#include "ppOp.h"
int main()
{
FILE *fpr, *fpw;
int wid_alig16 = ((SRC_WIDTH+15)&(~0xf));
int hei_alig16 = ((SRC_HEIGHT+15)&(~0xf));
int src_vir_width = 1920;//2048;
int src_vir_height = 1088;//1088;
int dst_vir_width = 800;//800;
int dst_vir_height = 1280;//1280;
int framecnt = 0;
char *tmpbuf = (char *)malloc(src_vir_width*src_vir_height/2);
RK_S32 ret = 0, i, j;
ALOGI("ppOp test start\n");
VPUMemLinear_t src, dst;
android::PP_OP_HANDLE hnd;
int vpuFd = VPUClientInit(VPU_PP);
ret |= VPUMallocLinear(&src, src_vir_width*src_vir_height*2);//SRC_SIZE);
ret |= VPUMallocLinear(&dst, dst_vir_width*dst_vir_height*2);//DST_SIZE);
if (ret) {
ALOGE("failed to malloc vpu_mem");
goto end;
}
if (vpuFd < 0) {
ALOGE("failed to open vpu client");
goto end;
}
{
#if 0
int i, j;
char *tmp = (char *)src.vir_addr;
for(i=0; i<SRC_HEIGHT; i++)
{
memset(tmp, (i&0xff), SRC_WIDTH);
tmp += SRC_WIDTH;
}
#endif
#if 1
char *tmp = (char *)src.vir_addr;
fpr = fopen("/sdcard/testin.yuv", "rb");
for(i=0; i<SRC_HEIGHT; i++)
{
if(fpr)fread(tmp, 1, SRC_WIDTH, fpr);
tmp += src_vir_width;
}
tmp = (char *)src.vir_addr;
if(fpr)fread(&tmp[src_vir_width*src_vir_height], 1, SRC_WIDTH*SRC_HEIGHT/2, fpr);
if(fpr)fclose(fpr);
for(i=0; i<SRC_HEIGHT/2; i++) //planar to semi planar
{
for(j=0; j<SRC_WIDTH/2; j++) //planar to semi planar
{
tmpbuf[i*src_vir_width+j*2+0] = tmp[src_vir_width*src_vir_height + i*SRC_WIDTH/2 + j];
tmpbuf[i*src_vir_width+j*2+1] = tmp[src_vir_width*src_vir_height + SRC_WIDTH*SRC_HEIGHT/4 + i*SRC_WIDTH/2 + j];
}
}
memcpy(&tmp[src_vir_width*src_vir_height], tmpbuf, src_vir_width*src_vir_height/2);
//memset(&tmp[SRC_WIDTH*SRC_HEIGHT], 0x80, SRC_WIDTH*SRC_HEIGHT/2);
#endif
VPUMemClean(&src);
}
while(1)
{
printf("framecnt=%d\n", framecnt);
if(framecnt++ >= 1)
break;
wid_alig16 = ((SRC_WIDTH+15)&(~0xf));
hei_alig16 = ((SRC_HEIGHT+15)&(~0xf));
android::PP_OPERATION opt;
memset(&opt, 0, sizeof(opt));
opt.srcAddr = src.phy_addr;
opt.srcFormat = PP_IN_FORMAT_YUV420SEMI;
opt.srcWidth = SRC_WIDTH;
opt.srcHeight = SRC_HEIGHT;
opt.srcHStride = src_vir_width;
opt.srcVStride = src_vir_height;
opt.srcX = 0;
opt.srcY = 0;
if(wid_alig16 != SRC_WIDTH)
opt.srcCrop8R = 1;
if(hei_alig16 != SRC_HEIGHT)
opt.srcCrop8D= 1;
wid_alig16 = ((DST_WIDTH+15)&(~0xf));
hei_alig16 = ((DST_HEIGHT+15)&(~0xf));
opt.dstAddr = dst.phy_addr;
opt.dstFormat = PP_OUT_FORMAT_YUV420INTERLAVE;
opt.dstWidth = DST_WIDTH;
opt.dstHeight = DST_HEIGHT;
opt.dstHStride = dst_vir_width;
opt.dstVStride = dst_vir_height;
opt.dstX = 0;
opt.dstY = 0;
opt.deinterlace = 0;
opt.rotation = PP_ROTATION_RIGHT_90;//PP_ROTATION_RIGHT_90;//PP_ROTATION_RIGHT_90;//PP_ROTATION_RIGHT_90;
opt.vpuFd = vpuFd;
ret |= android::ppOpInit(&hnd, &opt);
if (ret) {
ALOGE("ppOpInit failed");
hnd = NULL;
goto end;
}
ret = android::ppOpPerform(hnd);
if (ret) {
ALOGE("ppOpPerform failed");
}
ret = android::ppOpSync(hnd);
if (ret) {
ALOGE("ppOpSync failed");
}
ret = android::ppOpRelease(hnd);
if (ret) {
ALOGE("ppOpPerform failed");
}
VPUMemInvalidate(&dst);
{
#if 0
int i, j, ret = 0;
char *tmp = (char *)dst.vir_addr;
/*for(i=0; i<3; i++)
{
printf("col out_pos=%d, 0x%x\n", i*DST_WIDTH, tmp[i*DST_WIDTH]);
}
for(i=0; i<3; i++)
{
printf("las out_pos=%d, 0x%x\n", (DST_HEIGHT-1-i)*DST_WIDTH, tmp[(DST_HEIGHT-1-i)*DST_WIDTH]);
}*/
for(i=0; i<DST_HEIGHT; i++)
{
for(j=0; j<DST_WIDTH; j++)
{
if( tmp[i*DST_WIDTH + j] != (i&0xff))
ret = 1;
}
}
if( ret)
printf("framecount=%d pp operation is failed!\n", (framecnt-1));
else
printf("framecount=%d pp operation is suceess!\n", (framecnt-1));
memset(dst.vir_addr, 0xff, DST_SIZE);
VPUMemClean(&dst);
#endif
#if 1
char *tmp = (char *)dst.vir_addr;
//memset(&tmp[DST_WIDTH*DST_HEIGHT], 0x80, DST_WIDTH*DST_HEIGHT/2);
//VPUMemClean(&dst);
fpw = fopen("/data/testout.yuv", "wb+");
if(fpw)fwrite((char *)(dst.vir_addr), 1, dst_vir_width*dst_vir_height*3/2, fpw);
if(fpw)fclose(fpw);
#endif
}
}
end:
if(tmpbuf)free(tmpbuf);
if (src.phy_addr) VPUFreeLinear(&src);
if (dst.phy_addr) VPUFreeLinear(&dst);
if (vpuFd > 0) VPUClientRelease(vpuFd);
ALOGI("ppOp test end\n");
return 0;
}
#endif