root/src/add-ons/accelerants/ati/mach64_overlay.cpp
/*
        Haiku ATI video driver adapted from the X.org ATI driver which has the
        following copyright:

        Copyright 2003 through 2004 by Marc Aurele La France, tsi@xfree86.org

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

        Authors:
        Gerald Zajac
*/

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



bool
Mach64_DisplayOverlay(const overlay_window* window,
                                                const overlay_buffer* buffer)
{
        // Return true if setup is successful.

        SharedInfo& si = *gInfo.sharedInfo;

        if (window == NULL || buffer == NULL)
                return false;

        uint32 videoFormat;

        if (buffer->space == B_YCbCr422)
                videoFormat = SCALE_IN_VYUY422;
        else
                return false;   // color space not supported

        int32 x1 = (window->h_start < 0) ? 0 : window->h_start;
        int32 y1 = (window->v_start < 0) ? 0 : window->v_start;

        int32 x2 = window->h_start + window->width - 1;
        int32 y2 = window->v_start + window->height - 1;

        if (x2 > si.displayMode.timing.h_display)
                x2 = si.displayMode.timing.h_display;

        if (y2 > si.displayMode.timing.v_display)
                y2 = si.displayMode.timing.v_display;

        // If window is moved beyond edge of screen, do not allow width < 4 or
        // height < 4;  otherwise there is a possibilty of divide by zero when
        // computing the scale factors..
        if (x2 < x1 + 4)
                x2 = x1 + 4;

        if (y2 < y1 + 4)
                y2 = y1 + 4;

        // Calculate overlay scale factors.
        uint32 horzScale = (buffer->width << 12) / (x2 - x1 + 1);
        uint32 vertScale = (buffer->height << 12) / (y2 - y1 + 1);
        
        if (horzScale > 0xffff)         // only 16 bits are used for scale factors
                horzScale = 0xffff;
        if (vertScale > 0xffff)
                vertScale = 0xffff;

        gInfo.WaitForFifo(2);
        OUTREG(BUS_CNTL, INREG(BUS_CNTL) | BUS_EXT_REG_EN);     // enable reg block 1
        OUTREG(OVERLAY_SCALE_CNTL, SCALE_EN);   // reset the video

        if (si.chipType >= MACH64_264GTPRO) {
                const uint32 brightness = 0;
                const uint32 saturation = 12;

                gInfo.WaitForFifo(6);
                OUTREG(SCALER_COLOUR_CNTL, brightness | saturation << 8
                        | saturation << 16);
                OUTREG(SCALER_H_COEFF0, 0x0002000);
                OUTREG(SCALER_H_COEFF1, 0xd06200d);
                OUTREG(SCALER_H_COEFF2, 0xd0a1c0d);
                OUTREG(SCALER_H_COEFF3, 0xc0e1a0c);
                OUTREG(SCALER_H_COEFF4, 0xc14140c);
        }

        uint32 keyColor = 0;
        uint32 keyMask = 0;

        switch (si.displayMode.bitsPerPixel) {
                case 15:
                        keyMask = 0x7fff;
                        keyColor = (window->blue.value & window->blue.mask) << 0
                                | (window->green.value & window->green.mask) << 5
                                | (window->red.value & window->red.mask) << 10;
                                // 15 bit color has no alpha bits
                        break;
                case 16:
                        keyMask = 0xffff;
                        keyColor = (window->blue.value & window->blue.mask) << 0
                                | (window->green.value & window->green.mask) << 5
                                | (window->red.value & window->red.mask) << 11;
                                // 16 bit color has no alpha bits
                        break;
                default:
                        keyMask = 0xffffffff;
                        keyColor = (window->blue.value & window->blue.mask) << 0
                                | (window->green.value & window->green.mask) << 8
                                | (window->red.value & window->red.mask) << 16
                                | (window->alpha.value & window->alpha.mask) << 24;
                        break;
        }

        gInfo.WaitForFifo(3);
        OUTREG(OVERLAY_GRAPHICS_KEY_MSK, keyMask);
        OUTREG(OVERLAY_GRAPHICS_KEY_CLR, keyColor);
        OUTREG(OVERLAY_KEY_CNTL, OVERLAY_MIX_FALSE | OVERLAY_MIX_EQUAL);

        gInfo.WaitForFifo(8);
        OUTREG(OVERLAY_Y_X_START, OVERLAY_LOCK_START | (x1 << 16) | y1);
        OUTREG(OVERLAY_Y_X_END, (x2 << 16) | y2);
        OUTREG(OVERLAY_SCALE_INC, (horzScale << 16) | vertScale);
        OUTREG(SCALER_HEIGHT_WIDTH, (buffer->width << 16) | buffer->height);
        OUTREG(VIDEO_FORMAT, videoFormat);

        // Compute offset of overlay buffer in the video memory.
        uint32 offset = (uint32)((addr_t)buffer->buffer - si.videoMemAddr);

        if (si.chipType < MACH64_264VTB) {
                OUTREG(BUF0_OFFSET, offset);
                OUTREG(BUF0_PITCH, buffer->width);
        } else {
                OUTREG(SCALER_BUF0_OFFSET, offset);
                OUTREG(SCALER_BUF0_PITCH, buffer->width);
        }

        OUTREG(OVERLAY_SCALE_CNTL, SCALE_PIX_EXPAND | OVERLAY_EN | SCALE_EN);

        return true;
}


void
Mach64_StopOverlay(void)
{
        OUTREG(OVERLAY_SCALE_CNTL, SCALE_EN);   // reset the video
}