/****************************************************************************
 * Rage 128 Chapter 7 sample code                                           *
 *                                                                          *
 * ov1calcs.c - This module calculates the bandwidth available in the       *
 *              horizontal blank that can be used by the overlay/scaler.    *
 *                                                                          *
 * Copyright (c) 1999 ATI Technologies Inc. All rights reserved.            *
 ****************************************************************************/
#include "overlay.h"

void CalcScalerHBlank (
    DWORD SURFACE_FORMAT,
    DWORD rDestRight,
    DWORD rDestLeft,
    DWORD PrimaryPixelDepthInBytes,
    DWORD HTOTAL_InCharactersMinusOne,

    DWORD OV0_P1_X_END,
    DWORD OV0_P2_X_END,

    double XCLKPeriodInNSec,
    double VCLKPeriodInNSec,
    double ECPPeriodInNSec,
    DWORD ECP_DivideDownFactor,

    DWORD *EarliestDataTransfer,
    DWORD *LatestDataTransfer,
    DWORD *VCLK_Offset
)
{
    DWORD OctWordsPerLineMinusOne;
    double LineWriteTimeInVCLKs;
    double LineReadTimeInVCLKs;

    DWORD PCLK_DivideDownFactor;
    DWORD DisplayPipeLen;
    DWORD ScalerPipeLen;

#if 0
    /* Calculate the points (relative the the horizonal pixel count) where the scaler blank starts and ends. */
    /* This data is useful for figuring out how much time there is to begin fetching data into the scaler's line buffers. */

    /* We need to determine the earliest point in time that we can load new line(s). */
    /* If we load too early we will overwrite the existing line before the scaler is finished using it. */
    /* If we load too late, we waste memory cycles. */

    /* |        |<---------->| <--- LineReadTime */
    /* |                |<--->| <-- LineWriteTime */
    /* |                     /# */
    /* |  Read Pointer     / # */
    /* |              \  /  # */
    /* |               /   # */
    /* |             /    # \ */
    /* |           /     #   Write Pointer */
    /* |         /      # */
    /* +--------s-------*----e------------------ Time -> */
    /*         /        |     \ */
    /*  X Start  EarliestData  X End */
    /*             Transfer */

    /* There is an issue here in that the read and write pointer tragectories depend of whether the user zooms in on the source or not. */
    /* The worst case is probably full screen; however, as the user zooms, the "EarliestDataTransfer" value returned will change. */
    /* I believe that any changes resulting from this calculation are double buffered, so there isn't much of a problem. */
#endif

    switch (SURFACE_FORMAT)
    {
        case 9:
        case 10:    /* For planer modes we will assume that an entire line of U is fetched followed by an entire line of V. No Y data is fetched. */
                    OctWordsPerLineMinusOne = (int)(OV0_P2_X_END / 16);
                    break;
        case 13:
        case 14:    /* For these modes, the packed UV line is the same and the Y line. */
                    OctWordsPerLineMinusOne = (int)(OV0_P1_X_END / 16);
                    break;
        case 6:     /* 4 Byte Per Pix Format (RGB32) */
                    OctWordsPerLineMinusOne = (int)(OV0_P1_X_END / 4);
                    break;
        case 3:
        case 4:
        case 11:
        case 12:    /* 2 Byte Per Pix Formats (RGB15, RGB16, YUYV, VYUY) */
                    OctWordsPerLineMinusOne = (int)(OV0_P1_X_END / 8);
                    break;
        default:    /*{CYCACC_ASSERT(0, "Image format not supported by hardware")} */
                    break;
    }

    LineWriteTimeInVCLKs = OctWordsPerLineMinusOne * XCLKPeriodInNSec / VCLKPeriodInNSec;
    LineReadTimeInVCLKs = (rDestRight - rDestLeft + 1);

    /* There is a small block in the hardware (called OVERLAY) that translates rDestLeft into an HCount */
    /* comparator value that will trigger the overlay to start. */

    switch (PrimaryPixelDepthInBytes)
    {
        case 1: PCLK_DivideDownFactor = 8;
            break;
        case 2: PCLK_DivideDownFactor = 4;
            break;
        case 3: PCLK_DivideDownFactor = 2;
            break;
        case 4: PCLK_DivideDownFactor = 2;
            break;
        default: break;
    }

    DisplayPipeLen = 3;
    ScalerPipeLen = 19;
    *VCLK_Offset = DisplayPipeLen * PCLK_DivideDownFactor - ScalerPipeLen * ECP_DivideDownFactor + 4;

    if (LineReadTimeInVCLKs > LineWriteTimeInVCLKs)
    {
        /* The case in the figure above */
        *EarliestDataTransfer = (DWORD)(rDestRight - LineWriteTimeInVCLKs) + *VCLK_Offset;
    }
    else
    {
        *EarliestDataTransfer = rDestRight + *VCLK_Offset;
    }

    /* The scaler begins reading data from it's line buffers 16 ECP cycles before it begins generating an active line because */
    /* it has some small internal FIFOs that it needs to prefill with data from the line buffer. */
    *LatestDataTransfer = (HTOTAL_InCharactersMinusOne + 1)*8 + rDestLeft - 16*ECP_DivideDownFactor + *VCLK_Offset;
}
