root/src/add-ons/accelerants/3dfx/3dfx_overlay.cpp
/*
 * Copyright 2010 Haiku, Inc.  All rights reserved.
 * Distributed under the terms of the MIT license.
 *
 * Authors:
 *              Gerald Zajac
 */

#include "accelerant.h"
#include "3dfx.h"



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

        SharedInfo& si = *gInfo.sharedInfo;

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

        if (window->flags & B_OVERLAY_COLOR_KEY) {
                uint32 color = 0;

                if (si.displayMode.bitsPerPixel == 16) {
                        color = (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
                } else {
                        color = (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;
                }

                TDFX_WaitForFifo(2);
                OUTREG32(VIDEO_CHROMA_MIN, color);
                OUTREG32(VIDEO_CHROMA_MAX, color);
        }

        uint32 videoConfig = INREG32(VIDEO_PROC_CONFIG);
        videoConfig &= ~VIDEO_PROC_CONFIG_MASK;
        videoConfig |= (0x00000320 | OVERLAY_CLUT_BYPASS);

        // Scale image if window dimension is larger than the buffer dimension.
        // Scaling is not done if window dimension is smaller since the chip only
        // scales up to a larger dimension, and does not scale down to a smaller
        // dimension.

        if (window->width > buffer->width)
                videoConfig |= (1 << 14);
        if (window->height > buffer->height)
                videoConfig |= (1 << 15);

        switch (buffer->space) {
                case B_YCbCr422:
                        videoConfig |= VIDCFG_OVL_FMT_YUYV422;
                        break;
                case B_RGB16:
                        videoConfig |= VIDCFG_OVL_FMT_RGB565;
                        break;
                default:
                        return false;   // color space not supported
        }

        // can't do bilinear filtering when in 2X mode
        if ((videoConfig & VIDEO_2X_MODE_ENABLE) == 0)
                videoConfig |= (3 << 16);

        TDFX_WaitForFifo(1);
        OUTREG32(VIDEO_PROC_CONFIG, videoConfig);

        // Subtract 1 from height to eliminate junk on last line of image.
        int32 dudx = (buffer->width << 20) / window->width;
        int32 dudy = ((buffer->height - 1) << 20) / window->height;

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

        int32 x2 = x1 + window->width - 1;
        int32 y2 = y1 + window->height - 1;

        TDFX_WaitForFifo(6);

        // Set up coordinates of overlay window on screen.
        OUTREG32(VIDEO_OVERLAY_START_COORDS, x1 | (y1 << 12));
        OUTREG32(VIDEO_OVERLAY_END_COORDS, x2 | (y2 << 12));
        // Set up scale and position of overlay in graphics memory.
        OUTREG32(VIDEO_OVERLAY_DUDX, dudx);
        OUTREG32(VIDEO_OVERLAY_DUDX_OFFSET_SRC_WIDTH, ((x1 & 0x0001ffff) << 3)
                | (buffer->width << 20));
        OUTREG32(VIDEO_OVERLAY_DVDY, dudy);
        OUTREG32(VIDEO_OVERLAY_DVDY_OFFSET, (y1 & 0x0000ffff) << 3);

        // Add width of overlay buffer to stride.
        uint32 stride = INREG32(VIDEO_DESKTOP_OVERLAY_STRIDE) & 0x0000ffff;
        stride |= (buffer->width << 1) << 16;
        uint32 offset = (uint32)(addr_t)buffer->buffer_dma;

        TDFX_WaitForFifo(2);

        OUTREG32(VIDEO_DESKTOP_OVERLAY_STRIDE, stride);
        OUTREG32(VIDEO_IN_ADDR0, offset);

        return true;
}


void
TDFX_StopOverlay(void)
{
        // reset the video
        uint32 videoConfig = INREG32(VIDEO_PROC_CONFIG) & ~VIDEO_PROC_CONFIG_MASK;
        OUTREG32(VIDEO_PROC_CONFIG, videoConfig);
        OUTREG32(RGB_MAX_DELTA, 0x0080808);
}