/* * 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 */ #include "tng_vld_dec.h" #include "psb_drv_debug.h" #include #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); } }