Subversion Repositories freemyipod

Rev

Blame | Last modification | View Log | RSS feed

#include "global.h"
#include "interface/framebuffer/framebuffer.h"
#include "sys/util.h"

const uint8_t framebuffer_format_wordsize[] =
{
    [FRAMEBUFFER_FORMAT_I1] = 1,
    [FRAMEBUFFER_FORMAT_X1R1G1B1] = 4,
    [FRAMEBUFFER_FORMAT_I1R1G1B1] = 4,
    [FRAMEBUFFER_FORMAT_X7I1] = 8,
    [FRAMEBUFFER_FORMAT_X5R1G1B1] = 8,
    [FRAMEBUFFER_FORMAT_X2R2G2B2] = 8,
    [FRAMEBUFFER_FORMAT_R2G3B3] = 8,
    [FRAMEBUFFER_FORMAT_X1R5G5B5_LE] = 16,
    [FRAMEBUFFER_FORMAT_X1R5G5B5_BE] = 16,
    [FRAMEBUFFER_FORMAT_R5G6B5_LE] = 16,
    [FRAMEBUFFER_FORMAT_R5G6B5_BE] = 16,
    [FRAMEBUFFER_FORMAT_R8G8B8_LE] = 24,
    [FRAMEBUFFER_FORMAT_R8G8B8_BE] = 24,
    [FRAMEBUFFER_FORMAT_X31I1_LE] = 32,
    [FRAMEBUFFER_FORMAT_X31I1_BE] = 32,
    [FRAMEBUFFER_FORMAT_X8R8G8B8_LE] = 32,
    [FRAMEBUFFER_FORMAT_X8R8G8B8_BE] = 32,
};

uint32_t framebuffer_color_to_rgb888_be(enum framebuffer_format format, uint32_t color)
{
    uint32_t result = 0xff;
    switch (format)
    {
    case FRAMEBUFFER_FORMAT_X31I1_LE:
        color = swap32(color);
    case FRAMEBUFFER_FORMAT_I1:
    case FRAMEBUFFER_FORMAT_X7I1:
    case FRAMEBUFFER_FORMAT_X31I1_BE:
        result = (color & 1) ? 0xffffff : 0;
        break;
    case FRAMEBUFFER_FORMAT_I1R1G1B1:
        result = (color & 8) ? 0xff : 0x7f;
    case FRAMEBUFFER_FORMAT_X1R1G1B1:
    case FRAMEBUFFER_FORMAT_X5R1G1B1:
        result = ((color & 4) ? (result << 16) : 0) | ((color & 2) ? (result << 8) : 0) | ((color & 1) ? result : 0);
        break;
    case FRAMEBUFFER_FORMAT_X2R2G2B2:
        result = ((color & 0x30) << 18) | ((color & 0xc) << 14) | ((color & 3) << 6);
        result |= result >> 2;
        result |= result >> 4;
        break;
    case FRAMEBUFFER_FORMAT_R2G3B3:
        result = ((color & 0xc0) << 16) | ((color & 0x38) << 10) | ((color & 7) << 5);
        result |= (result & 0xc00000) >> 2;
        result |= (result & 0xf00000) >> 4;
        result |= (result & 0xe0e0) >> 3;
        result |= (result & 0xc0c0) >> 6;
        break;
    case FRAMEBUFFER_FORMAT_X1R5G5B5_LE:
        color = swap16(color);
    case FRAMEBUFFER_FORMAT_X1R5G5B5_BE:
        result = ((color & 0x7c00) << 9) | ((color & 0x3e0) << 6) | ((color & 0x1f) << 3);
        result |= (result & 0xe0e0e0) >> 5;
        break;
    case FRAMEBUFFER_FORMAT_R5G6B5_LE:
        color = swap16(color);
    case FRAMEBUFFER_FORMAT_R5G6B5_BE:
        result = ((color & 0xf800) << 8) | ((color & 0x7e0) << 5) | ((color & 0x1f) << 3);
        result |= (result & 0xe000e0) >> 5;
        result |= (result & 0xc000) >> 6;
        break;
    case FRAMEBUFFER_FORMAT_R8G8B8_LE:
        color <<= 8;
    case FRAMEBUFFER_FORMAT_X8R8G8B8_LE:
        color = swap32(color);
    case FRAMEBUFFER_FORMAT_R8G8B8_BE:
    case FRAMEBUFFER_FORMAT_X8R8G8B8_BE:
        result = color;
    }
    return result;
}

uint32_t framebuffer_color_from_rgb888_be(enum framebuffer_format format, uint32_t color)
{
    uint32_t result = 0;
    uint8_t r = (color & 0xff0000) >> 16;
    uint8_t g = (color & 0xff00) >> 8;
    uint8_t b = color & 0xff;
    switch (format)
    {
    case FRAMEBUFFER_FORMAT_I1:
    case FRAMEBUFFER_FORMAT_X7I1:
    case FRAMEBUFFER_FORMAT_X31I1_BE:
        result = r + g + b >= 0x180 ? 1 : 0;
        break;
    case FRAMEBUFFER_FORMAT_X31I1_LE:
        result = r + g + b >= 0x180 ? 0x01000000 : 0;
        break;
    case FRAMEBUFFER_FORMAT_X1R1G1B1:
    case FRAMEBUFFER_FORMAT_X5R1G1B1:
        result = ((r & 0x80) >> 5) | ((g & 0x80) >> 6) | ((b & 0x80) >> 7);
        break;
    case FRAMEBUFFER_FORMAT_I1R1G1B1:
        result = r + g + b >= 0x180 ? (8 | (r >= 0x80 ? 4 : 0) | (g >= 0x80 ? 2 : 0) | (b >= 0x80 ? 1 : 0))
                                    : ((r >= 0x40 ? 4 : 0) | (g >= 0x40 ? 2 : 0) | (b >= 0x40 ? 1 : 0));
        break;
    case FRAMEBUFFER_FORMAT_X2R2G2B2:
        result = (((r - (r >> 2)) >> 6) << 4) | (((g - (g >> 2)) >> 6) << 2) | ((b - (b >> 2)) >> 6);
        break;
    case FRAMEBUFFER_FORMAT_R2G3B3:
        result = (((r - (r >> 2)) >> 6) << 6) | (((g - (g >> 3)) >> 5) << 3) | ((b - (b >> 3)) >> 5);
        break;
    case FRAMEBUFFER_FORMAT_X1R5G5B5_BE:
        result = (((r - (r >> 5)) >> 3) << 10) | (((g - (g >> 5)) >> 3) << 5) | ((b - (b >> 5)) >> 3);
        break;
    case FRAMEBUFFER_FORMAT_X1R5G5B5_LE:
        result = swap16((((r - (r >> 5)) >> 3) << 10) | (((g - (g >> 5)) >> 3) << 5) | ((b - (b >> 5)) >> 3));
        break;
    case FRAMEBUFFER_FORMAT_R5G6B5_BE:
        result = (((r - (r >> 5)) >> 3) << 11) | (((g - (g >> 6)) >> 2) << 5) | ((b - (b >> 5)) >> 3);
        break;
    case FRAMEBUFFER_FORMAT_R5G6B5_LE:
        result = swap16((((r - (r >> 5)) >> 3) << 11) | (((g - (g >> 6)) >> 2) << 5) | ((b - (b >> 5)) >> 3));
        break;
    case FRAMEBUFFER_FORMAT_R8G8B8_LE:
        color <<= 8;
    case FRAMEBUFFER_FORMAT_X8R8G8B8_LE:
        color = swap32(color);
    case FRAMEBUFFER_FORMAT_R8G8B8_BE:
    case FRAMEBUFFER_FORMAT_X8R8G8B8_BE:
        result = color;
        break;
    }
    return result;
}

uint32_t framebuffer_convert_color(enum framebuffer_format from, enum framebuffer_format to, uint32_t color)
{
    return framebuffer_color_from_rgb888_be(to, framebuffer_color_to_rgb888_be(from, color));
}

uint32_t framebuffer_get_pixel(const struct framebuffer_instance* instance, int x, int y)
{
    int wsize = framebuffer_format_wordsize[instance->format];
    int bit = (instance->width * y + x) * wsize;
    uint32_t color = (swap32(((uint32_t*)instance->data)[bit >> 5]) >> (32 - (bit & 31) - wsize)) & (0xffffffff >> (32 - wsize));
    if (wsize == 16) return swap16(color);
    if (wsize == 32) return swap32(color);
    return color;
}

void framebuffer_set_pixel(const struct framebuffer_instance* instance, int x, int y, uint32_t color)
{
    int wsize = framebuffer_format_wordsize[instance->format];
    if (wsize == 16) color = swap16(color);
    else if (wsize == 32) color = swap32(color);
    int bit = (instance->width * y + x) * wsize;
    int byte = bit >> 5;
    bit = 32 - (bit & 31) - wsize;
    uint32_t mask = 0xffffffff >> (32 - wsize);
    uint32_t data = swap32(((uint32_t*)instance->data)[byte]);
    ((uint32_t*)instance->data)[byte] = swap32((data & ~(mask << bit)) | ((color & mask) << bit));
}

void framebuffer_fill(const struct framebuffer_instance* instance, int x, int y, int w, int h,
                      enum framebuffer_format format, uint32_t color, enum framebuffer_conversion_quality quality)
{
    int stride = instance->width;
    enum framebuffer_format fmt = instance->format;
    int wsize = framebuffer_format_wordsize[fmt];
    if (format != fmt)
    {
        if (framebuffer_format_wordsize[format] == 16) color = swap16(color);
        else if (framebuffer_format_wordsize[format] == 32) color = swap32(color);
        color = framebuffer_convert_color(format, fmt, color);
        if (wsize == 16) color = swap16(color);
        else if (wsize == 32) color = swap32(color);
    }

    if (w == stride)
    {
        w *= h;
        h = 1;
    }

    color &= 0xffffffff >> (32 - wsize);
    while (wsize < 32 && !(w & 1) && !(x & 1) && !(stride & 1))
    {
        color |= color << wsize;
        wsize <<= 1;
        w >>= 1;
        x >>= 1;
        stride >>= 1;
    }
    if (wsize >= 8)
    {
        void* out = instance->data + (y * stride + x) * (wsize >> 3);
        while (h--)
        {
            if (wsize == 32)
            {
                uint32_t* ptr = out;
                int pixels = w;
                while (pixels--) *ptr++ = color;
            }
            else if (wsize == 16)
            {
                uint16_t* ptr = out;
                int pixels = w;
                while (pixels--) *ptr++ = color;
            }
            else memset(out, color, w);
            out += stride * (wsize >> 3);
        }
        return;
    }

    int mask = 0xffffffff >> (32 - wsize);
    uint32_t* out = instance->data;
    int bit = (y * stride + x) * wsize;
    out += bit >> 5;
    bit &= 31;
    while (h--)
    {
        int pixels = w;
        uint32_t data = swap32(*out);
        while (pixels--)
        {
            if (!bit) data = swap32(*out);
            data = (data & ~(mask << (32 - bit - wsize))) | (color << (32 - bit - wsize));
            bit += wsize;
            if (bit == 32)
            {
                *out++ = swap32(data);
                bit = 0;
            }
        }
        if (bit) *out = swap32(data);
        bit += (stride - w) * wsize;
        out += bit >> 5;
        bit &= 31;
    }
}

void framebuffer_blit(const struct framebuffer_instance* infb, int inx, int iny,
                      const struct framebuffer_instance* outfb, int outx, int outy,
                      int w, int h, enum framebuffer_conversion_quality quality)
{
    int instride = infb->width;
    int outstride = outfb->width;
    enum framebuffer_format infmt = infb->format;
    enum framebuffer_format outfmt = outfb->format;
    int inwsize = framebuffer_format_wordsize[infmt];
    int outwsize = framebuffer_format_wordsize[outfmt];

    if (w == instride && w == outstride)
    {
        w *= h;
        h = 1;
    }

    if (infmt == outfmt)
    {
        while (inwsize < 32 && !(w & 1) && !(inx & 1) && !(outx & 1) && !(instride & 1) && !(outstride & 1))
        {
            inwsize <<= 1;
            outwsize <<= 1;
            w >>= 1;
            inx >>= 1;
            outx >>= 1;
            instride >>= 1;
            outstride >>= 1;
        }
        if (inwsize >= 8)
        {
            void* in = infb->data + (iny * instride + inx) * (inwsize >> 3);
            void* out = outfb->data + (outy * outstride + outx) * (outwsize >> 3);
            while (h--)
            {
                memcpy(out, in, w * (outwsize >> 3));
                in += (instride - w) * (inwsize >> 3);
                out += (outstride - w) * (outwsize >> 3);
            }
            return;
        }
    }

    int inmask = 0xffffffff >> (32 - inwsize);
    int outmask = 0xffffffff >> (32 - outwsize);
    uint32_t* in = infb->data;
    uint32_t* out = outfb->data;
    int inbit = (iny * instride + inx) * inwsize;
    int outbit = (outy * outstride + outx) * outwsize;
    in += inbit >> 5;
    out += outbit >> 5;
    inbit &= 31;
    outbit &= 31;
    while (h--)
    {
        int pixels = w;
        uint32_t idata = swap32(*in) << inbit;
        uint32_t odata = swap32(*out);
        while (pixels--)
        {
            if (inbit == 32)
            {
                idata = swap32(*++in);
                inbit = 0;
            }
            if (!outbit) odata = swap32(*out);
            idata = ((idata << inwsize) | (idata >> (32 - inwsize)));
            uint32_t data = idata & inmask;
            if (infmt != outfmt) data = framebuffer_convert_color(infmt, outfmt, data);
            odata = (odata & ~(outmask << (32 - outbit - outwsize))) | (data << (32 - outbit - outwsize));
            inbit += inwsize;
            outbit += outwsize;
            if (outbit == 32)
            {
                *out++ = swap32(odata);
                outbit = 0;
            }
        }
        if (outbit) *out = swap32(odata);
        inbit += (instride - w) * inwsize;
        outbit += (outstride - w) * outwsize;
        in += inbit >> 5;
        out += outbit >> 5;
        inbit &= 31;
        outbit &= 31;
    }
}

void framebuffer_update(const struct framebuffer_instance* instance, int x, int y, int w, int h)
{
    instance->update_handler(instance->update_handler_arg, instance, x, y, w, h);
}