root/src/add-ons/accelerants/ati/mach64_draw.cpp
/*
        Haiku ATI video driver adapted from the X.org ATI driver.

        Copyright 1992,1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Carolina.
        Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org

        Copyright 2009 Haiku, Inc.  All rights reserved.
        Distributed under the terms of the MIT license.

        Authors:
        Gerald Zajac 2009
*/


#include "accelerant.h"
#include "mach64.h"



void
Mach64_EngineReset()
{
        // Reset engine and then enable it.

        uint32 genTestCntl = INREG(GEN_TEST_CNTL) & ~GUI_ENGINE_ENABLE;
        OUTREG(GEN_TEST_CNTL, genTestCntl);
        OUTREG(GEN_TEST_CNTL, genTestCntl | GUI_ENGINE_ENABLE);

        // Ensure engine is not locked up by clearing any FIFO errors.

        OUTREG(BUS_CNTL, INREG(BUS_CNTL) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK);
}


void
Mach64_EngineInit(const DisplayModeEx& mode)
{
        // Initialize the drawing environment and clear the display.

        Mach64_EngineReset();

        gInfo.WaitForIdle();

        OUTREG(MEM_VGA_WP_SEL, 0x00010000);
        OUTREG(MEM_VGA_RP_SEL, 0x00010000);

        uint32 dpPixWidth = 0;
        uint32 dpChainMask = 0;

        switch (mode.bitsPerPixel) {
        case 8:
                dpPixWidth = HOST_8BPP | SRC_8BPP | DST_8BPP;
                dpChainMask = DP_CHAIN_8BPP;
                break;
        case 15:
                dpPixWidth = HOST_15BPP | SRC_15BPP | DST_15BPP;
                dpChainMask = DP_CHAIN_15BPP;
                break;
        case 16:
                dpPixWidth = HOST_16BPP | SRC_16BPP | DST_16BPP;
                dpChainMask = DP_CHAIN_16BPP;
                break;
        case 32:
                dpPixWidth = HOST_32BPP | SRC_32BPP | DST_32BPP;
                dpChainMask = DP_CHAIN_32BPP;
                break;
        }

        dpPixWidth |= BYTE_ORDER_LSB_TO_MSB;    // set for little-endian byte order

        gInfo.WaitForFifo(3);
        OUTREG(DP_PIX_WIDTH, dpPixWidth);
        OUTREG(DP_CHAIN_MASK, dpChainMask);

        OUTREG(CONTEXT_MASK, 0xffffffff);

        gInfo.WaitForFifo(7);
        OUTREG(DST_OFF_PITCH, (mode.timing.h_display / 8) << 22);
        OUTREG(DST_Y_X, 0);
        OUTREG(DST_HEIGHT, 0);
        OUTREG(DST_BRES_ERR, 0);
        OUTREG(DST_BRES_INC, 0);
        OUTREG(DST_BRES_DEC, 0);
        OUTREG(DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM | DST_LAST_PEL);

        gInfo.WaitForFifo(6);
        OUTREG(SRC_OFF_PITCH, (mode.timing.h_display / 8) << 22);
        OUTREG(SRC_Y_X, 0);
        OUTREG(SRC_HEIGHT1_WIDTH1, 0x10001);
        OUTREG(SRC_Y_X_START, 0);
        OUTREG(SRC_HEIGHT2_WIDTH2, 0x10001);
        OUTREG(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT);

        gInfo.WaitForFifo(7);
        OUTREGM(HOST_CNTL, 0, HOST_BYTE_ALIGN);
        OUTREG(PAT_REG0, 0);
        OUTREG(PAT_REG1, 0);
        OUTREG(PAT_CNTL, 0);

        OUTREG(SC_LEFT_RIGHT, ((mode.timing.h_display << 16) | 0 ));
        OUTREG(SC_TOP_BOTTOM, ((mode.timing.v_display << 16) | 0 ));

        gInfo.WaitForFifo(9);
        OUTREG(DP_BKGD_CLR, 0);
        OUTREG(DP_FRGD_CLR, 0xffffffff);
        OUTREG(DP_WRITE_MASK, 0xffffffff);
        OUTREG(DP_MIX, (MIX_SRC << 16) | MIX_DST);
        OUTREG(DP_SRC, FRGD_SRC_FRGD_CLR);

        OUTREG(CLR_CMP_CLR, 0);
        OUTREG(CLR_CMP_MASK, 0xffffffff);
        OUTREG(CLR_CMP_CNTL, 0);

        gInfo.WaitForIdle();
}


void
Mach64_FillRectangle(engine_token *et, uint32 color, fill_rect_params *pList, uint32 count)
{
        (void)et;               // avoid compiler warning for unused arg

        gInfo.WaitForFifo(4);
        OUTREG(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE);
        OUTREG(DP_FRGD_CLR, color);
        OUTREG(DP_MIX, (MIX_SRC << 16) | MIX_DST);
        OUTREG(DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM | DST_LAST_PEL);

        while (count--) {
                int x = pList->left;
                int y = pList->top;
                int w = pList->right - x + 1;
                int h = pList->bottom - y + 1;

                gInfo.WaitForFifo(2);
                OUTREG(DST_Y_X, (x << 16) | y);
                OUTREG(DST_HEIGHT_WIDTH, (w << 16) | h);

                pList++;
        }
}


void
Mach64_FillSpan(engine_token *et, uint32 color, uint16 *pList, uint32 count)
{
        (void)et;               // avoid compiler warning for unused arg

        gInfo.WaitForFifo(4);
        OUTREG(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE);
        OUTREG(DP_FRGD_CLR, color);
        OUTREG(DP_MIX, (MIX_SRC << 16) | MIX_DST);
        OUTREG(DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM | DST_LAST_PEL);

        while (count--) {
                int y = *pList++;
                int x = *pList++;
                int w = *pList++ - x + 1;

                if (w <= 0)
                        continue;       // discard span with zero or negative width

                gInfo.WaitForFifo(2);
                OUTREG(DST_Y_X, (x << 16) | y);
                OUTREG(DST_HEIGHT_WIDTH, (w << 16) | 1);
        }
}


void
Mach64_InvertRectangle(engine_token *et, fill_rect_params *pList, uint32 count)
{
        (void)et;               // avoid compiler warning for unused arg

        gInfo.WaitForFifo(3);
        OUTREG(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE);
        OUTREG(DP_MIX, MIX_NOT_DST << 16);
        OUTREG(DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM | DST_LAST_PEL);

        while (count--) {
                int x = pList->left;
                int y = pList->top;
                int w = pList->right - x + 1;
                int h = pList->bottom - y + 1;

                gInfo.WaitForFifo(2);
                OUTREG(DST_Y_X, (x << 16) | y);
                OUTREG(DST_HEIGHT_WIDTH, (w << 16) | h);

                pList++;
        }
}


void
Mach64_ScreenToScreenBlit(engine_token *et, blit_params *pList, uint32 count)
{
        (void)et;               // avoid compiler warning for unused arg

        gInfo.WaitForFifo(2);
        OUTREG(DP_SRC, FRGD_SRC_BLIT);
        OUTREG(DP_MIX, MIX_SRC << 16);

        while (count--) {
                int cmd = DST_LAST_PEL;
                int src_x = pList->src_left;
                int src_y = pList->src_top;
                int dest_x = pList->dest_left;
                int dest_y = pList->dest_top;
                int width = pList->width;
                int height = pList->height;

                if (dest_x <= src_x) {
                        cmd |= DST_X_LEFT_TO_RIGHT;
                } else {
                        src_x += width;
                        dest_x += width;
                }

                if (dest_y <= src_y) {
                        cmd |= DST_Y_TOP_TO_BOTTOM;
                } else {
                        src_y += height;
                        dest_y += height;
                }

                gInfo.WaitForFifo(5);
                OUTREG(DST_CNTL, cmd);
                OUTREG(SRC_Y_X, (src_x << 16) | src_y);
                OUTREG(SRC_HEIGHT1_WIDTH1, ((width + 1) << 16) | (height + 1));
                OUTREG(DST_Y_X, (dest_x << 16) | dest_y);
                OUTREG(DST_HEIGHT_WIDTH, ((width + 1) << 16) | (height + 1));

                pList ++;
        }
}