blob: 20dd4d4fae9b78d12803b0c847b4194aabec1b83 [file] [log] [blame]
/*
* Copyright (c) 2011 Intel Corporation. All Rights Reserved.
* Copyright (c) Imagination Technologies Limited, UK
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* Authors:
* Li Zeng <li.zeng@intel.com>
*/
#include "tng_vld_dec.h"
#include "psb_drv_debug.h"
#include <math.h>
#include "hwdefs/reg_io2.h"
#include "hwdefs/msvdx_offsets.h"
#include "hwdefs/msvdx_cmds_io2.h"
#define SCC_MAXTAP 9
#define SCC_MAXINTPT 16
static float tng_calculate_coeff_bessi0(float x)
{
float ax,ans;
float y;
ax = (float)fabs(x);
if (ax < 3.75)
{
y = (float)(x / 3.75);
y *= y;
ans = (float)(1.0 + y * (3.5156229 + y * (3.0899424 + y * (1.2067492
+ y * (0.2659732 + y * (0.360768e-1 + y * 0.45813e-2))))));
}
else
{
y = (float)(3.75 / ax);
ans = (float)((float)((sqrt(ax) / sqrt(ax)) * (0.39894228 + y * (0.1328592e-1
+ y * (0.225319e-2 + y * (-0.157565e-2 + y * (0.916281e-2
+y * (-0.2057706e-1 + y * (0.2635537e-1 + y * (-0.1647633e-1
+ y * 0.392377e-2))))))))));
}
return ans;
}
static float tng_calculate_coeff_sync_func( float fi,
float ft,
float fI,
float fT,
float fScale)
{
const float cfPI = 3.1415926535897f;
float fx, fIBeta, fBeta, fTempval, fSincfunc;
/* Kaiser window */
fx = ((ft * fI + fi) - (fT * fI / 2)) / (fT * fI / 2);
fBeta = 2.0f;
fIBeta = 1.0f/(tng_calculate_coeff_bessi0(fBeta));
fTempval = tng_calculate_coeff_bessi0(fBeta * (float)sqrt(1.0f - fx * fx)) * fIBeta;
/* Sinc function */
if ((fT / 2 - ft - fi / fI) == 0)
{
fSincfunc = 1.0f;
}
else
{
fx = 0.9f * fScale * cfPI * (fT / 2 - (ft + fi / fI));
fSincfunc = (float)(sin(fx) / fx);
}
return fSincfunc*fTempval;
}
/*
******************************************************************************
@Description
Calculates MSVDX scaler coefficients
@Input fPitch : Scale pitch
@Output Table : Table of coefficients
@Input I : Number of intpt? ( table dimension)
@Input T : Number of taps (table dimension)
******************************************************************************/
static void tng_calculate_scaler_coeff( float fPitch,
IMG_UINT8 Table[SCC_MAXTAP][SCC_MAXINTPT],
IMG_UINT32 I,
IMG_UINT32 T)
{
/* Due to the nature of the function we will only ever want to calculate the first half of the */
/* taps and the middle one (is this really a tap ?) as the seconda half are derived from the */
/* first half as the function is symetrical. */
float fScale = 1.0f / fPitch;
IMG_UINT32 i, t;
float flTable[SCC_MAXTAP][SCC_MAXINTPT];
IMG_INT32 nTotal;
float ftotal;
IMG_INT32 val;
IMG_INT32 mT, mI; /* mirrored / middle Values for I and T */
memset(flTable, 0.0, SCC_MAXTAP * SCC_MAXINTPT);
if (fScale > 1.0f)
{
fScale = 1.0f;
}
for (i = 0; i < I; i++)
{
for (t = 0; t < T; t++)
{
flTable[t][i] = 0.0;
}
}
for (i = 0;i < I; i++)
{
for (t = 0; t < T; t++)
{
flTable[t][i] = tng_calculate_coeff_sync_func((float)i, (float)t,
(float)I, (float)T, fScale);
}
}
if (T>2)
{
for (t = 0; t < ((T / 2) + (T % 2)); t++)
{
for (i=0 ; i < I; i++)
{
/* copy the table around the centrepoint */
mT = ((T - 1) - t) + (I - i) / I;
mI = (I - i) % I;
if (((IMG_UINT32)mI < I) && ((IMG_UINT32)mT < T) &&
((t < ((T / 2) + (T % 2) - 1)) || ((I - i) > ((T % 2) * (I / 2)))))
{
flTable[mT][mI] = flTable[t][i];
}
}
}
/* the middle value */
mT = T / 2;
if ((T % 2) != 0)
{
mI = I/2;
}
else
{
mI = 0;
}
flTable[mT][mI] = tng_calculate_coeff_sync_func(
(float) mI, (float) mT,
(float) I, (float) T, fScale);
}
/* normalize this interpolation point, and convert to 2.6 format trucating the result */
for (i = 0; i < I; i++)
{
nTotal = 0;
for (ftotal = 0,t = 0; t < T; t++)
{
ftotal += flTable[t][i];
}
for (t = 0; t < T; t++)
{
val = (IMG_UINT32) ((flTable[t][i] * 64.0f) / ftotal);
Table[t][i] = (IMG_UINT8) val;
nTotal += val;
}
if ((i <= (I / 2)) || (T <= 2)) /* normalize any floating point errors */
{
nTotal -= 64;
if ((i == (I / 2)) && (T > 2))
{
nTotal /= 2;
}
/* subtract the error from the I Point in the first tap */
/* ( this will not get mirrored, as it would go off the end ). */
Table[0][i] = (IMG_UINT8)(Table[0][i] - (IMG_UINT8) nTotal);
}
}
/* copy the normalised table around the centrepoint */
if (T > 2)
{
for ( t = 0; t < ((T / 2) + (T % 2)); t++)
{
for (i = 0; i < I; i++)
{
mT = ((T - 1) - t) + (I - i) / I;
mI = (I - i) % I;
if (((IMG_UINT32)mI < I) && ((IMG_UINT32)mT < T) && ((t < ((T / 2) + (T % 2) - 1)) || ((I - i) > ((T % 2) * (I / 2)))))
{
Table[mT][mI] = Table[t][i];
}
}
}
}
}
void tng_calculate_scaler_coff_reg(object_context_p obj_context)
{
context_DEC_p ctx = (context_DEC_p) obj_context->format_data;
object_surface_p src_surface = obj_context->current_render_target;
/* If the surfaces are smaller that the size the object was constructed with, then we need to downscale */
float fHorzPitch;
float fVertPitch;
int scale_acc = 11;
int i;
#ifndef PSBVIDEO_MFLD
scale_acc = 12;
#endif
drv_debug_msg(VIDEO_DEBUG_GENERAL, "content crop is %dx%d",
obj_context->driver_data->render_rect.width, obj_context->driver_data->render_rect.height);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "scaling dest is %dx%d",
obj_context->current_render_target->width_s, obj_context->current_render_target->height_s);
/* The unscaled dimensions in the pitch calculation below MUST match the Display Width and Height sent to the hardware */
fHorzPitch = obj_context->driver_data->render_rect.width / (float) obj_context->current_render_target->width_s;
fVertPitch = obj_context->driver_data->render_rect.height / (float) obj_context->current_render_target->height_s;
IMG_UINT32 reg_value;
IMG_UINT8 calc_table[4][16];
tng_calculate_scaler_coeff(fHorzPitch, calc_table, 16, 4);
for (i = 0; i < 4; i++)
{
unsigned int j = 1 + 2 * i;
reg_value = 0;
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, HORIZONTAL_LUMA_COEFFICIENTS, HOR_LUMA_COEFF_3, calc_table[0][j]);
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, HORIZONTAL_LUMA_COEFFICIENTS, HOR_LUMA_COEFF_2, calc_table[1][j]);
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, HORIZONTAL_LUMA_COEFFICIENTS, HOR_LUMA_COEFF_1, calc_table[2][j]);
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, HORIZONTAL_LUMA_COEFFICIENTS, HOR_LUMA_COEFF_0, calc_table[3][j]);
ctx->scaler_coeff_reg[/* Luma */ 0][/* Hori */ 0][i] = reg_value;
reg_value = 0;
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, HORIZONTAL_CHROMA_COEFFICIENTS, HOR_CHROMA_COEFF_3, calc_table[0][j]);
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, HORIZONTAL_CHROMA_COEFFICIENTS, HOR_CHROMA_COEFF_2, calc_table[1][j]);
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, HORIZONTAL_CHROMA_COEFFICIENTS, HOR_CHROMA_COEFF_1, calc_table[2][j]);
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, HORIZONTAL_CHROMA_COEFFICIENTS, HOR_CHROMA_COEFF_0, calc_table[3][j]);
ctx->scaler_coeff_reg[/* Chroma */ 1][/* H */ 0][i] = reg_value;
}
tng_calculate_scaler_coeff(fVertPitch, calc_table, 16, 4);
for (i = 0; i < 4; i++)
{
unsigned int j = 1+2*i;
reg_value = 0;
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, VERTICAL_LUMA_COEFFICIENTS, VER_LUMA_COEFF_3, calc_table[0][j]);
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, VERTICAL_LUMA_COEFFICIENTS, VER_LUMA_COEFF_2, calc_table[1][j]);
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, VERTICAL_LUMA_COEFFICIENTS, VER_LUMA_COEFF_1, calc_table[2][j]);
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, VERTICAL_LUMA_COEFFICIENTS, VER_LUMA_COEFF_0, calc_table[3][j]);
ctx->scaler_coeff_reg[/* L */ 0][/* Verti */ 1][i] = reg_value;
reg_value = 0;
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, VERTICAL_CHROMA_COEFFICIENTS, VER_CHROMA_COEFF_3, calc_table[0][j]);
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, VERTICAL_CHROMA_COEFFICIENTS, VER_CHROMA_COEFF_2,calc_table[1][j]);
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, VERTICAL_CHROMA_COEFFICIENTS, VER_CHROMA_COEFF_1, calc_table[2][j]);
REGIO_WRITE_FIELD(reg_value, MSVDX_CMDS, VERTICAL_CHROMA_COEFFICIENTS, VER_CHROMA_COEFF_0, calc_table[3][j]);
ctx->scaler_coeff_reg[/* C */ 1][ /* V */ 1][i] = reg_value;
}
/* VXD can only downscale from the original display size. */
IMG_ASSERT(fHorzPitch >= 1 && fVertPitch >= 1);
#ifdef PSBVIDEO_MRFL_DEC
scale_acc = 12;
#endif
ctx->h_scaler_ctrl = 0;
REGIO_WRITE_FIELD_LITE(ctx->h_scaler_ctrl, MSVDX_CMDS, HORIZONTAL_SCALE_CONTROL, HORIZONTAL_SCALE_PITCH, (int)(fHorzPitch * (1 << scale_acc)));
REGIO_WRITE_FIELD_LITE(ctx->h_scaler_ctrl, MSVDX_CMDS, HORIZONTAL_SCALE_CONTROL, HORIZONTAL_INITIAL_POS, (int)(fHorzPitch * 0.5f * (1 << scale_acc)));
ctx->v_scaler_ctrl = 0;
REGIO_WRITE_FIELD_LITE(ctx->v_scaler_ctrl, MSVDX_CMDS, VERTICAL_SCALE_CONTROL, VERTICAL_SCALE_PITCH, (int)(fVertPitch * (1 << scale_acc) + 0.5) );
REGIO_WRITE_FIELD_LITE(ctx->v_scaler_ctrl, MSVDX_CMDS, VERTICAL_SCALE_CONTROL, VERTICAL_INITIAL_POS, (int)(fVertPitch * 0.5 * (1 << scale_acc) + 0.5));
}
void tng_ved_write_scale_reg(object_context_p obj_context)
{
uint32_t cmd = 0;
psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
context_DEC_p ctx = (context_DEC_p) obj_context->format_data;
object_surface_p src_surface = obj_context->current_render_target;
unsigned int lc, hv, x;
/* setup scaling coeffs */
if (obj_context->scaling_update) {
tng_calculate_scaler_coff_reg(obj_context);
obj_context->scaling_update = 0;
}
{
psb_cmdbuf_rendec_start(cmdbuf, RENDEC_REGISTER_OFFSET(MSVDX_CMDS, SCALED_DISPLAY_SIZE));
cmd = 0;
REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS, SCALED_DISPLAY_SIZE, SCALE_DISPLAY_WIDTH, obj_context->driver_data->render_rect.width - 1);
REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS, SCALED_DISPLAY_SIZE, SCALE_DISPLAY_HEIGHT, obj_context->driver_data->render_rect.height - 1);
psb_cmdbuf_rendec_write(cmdbuf, cmd);
psb_cmdbuf_rendec_write(cmdbuf, ctx->h_scaler_ctrl );
psb_cmdbuf_rendec_write(cmdbuf, ctx->v_scaler_ctrl ); //58
psb_cmdbuf_rendec_end(cmdbuf);
}
/* Write the Coefficeients */
{
psb_cmdbuf_rendec_start(cmdbuf, RENDEC_REGISTER_OFFSET(MSVDX_CMDS, HORIZONTAL_LUMA_COEFFICIENTS));
for(lc=0 ; lc<2 ; lc++)
{
for(hv=0 ; hv<2 ; hv++)
{
for(x=0 ; x<4 ; x++)
{
psb_cmdbuf_rendec_write(cmdbuf, ctx->scaler_coeff_reg[lc][hv][x]);
}
}
}
psb_cmdbuf_rendec_end(cmdbuf);
}
}