C++程序  |  355行  |  12.98 KB

/*
 * 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);
    }
}