Android图形库Skia(二)-将图像输出到framebuffer

上一个例子是将最后的画面输出为png的图片。不够直观,这次结合framebuffer来显示,会直观的显示在LCD上。这次基于framebuffer skia 结合搭建GUI这个文章。

按照之前的了解 skia是故意不和底层相关,比如这次的framebuffer。这使得它可以只专心绘图,具体显示在哪里则不管。同样与参考了Skia and framebuffer。代码不贴了稍后上传,以下是运行截图:


我已经是激动不已了,迫不及待想要把freetype harfbuzz集成进来显示字体,看字体的渲染效果。

代码:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <string.h>
#include <errno.h>

#include "SkBitmap.h"
#include "SkDevice.h"
#include "SkPaint.h"
#include "SkRect.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkMatrix.h"
#include "SkImageEncoder.h"
#include "SkImageDecoder.h"

#ifndef __ANDROID__
#define FRAMEBUFFER "/dev/fb0"
#define OUT_DIR "/tmp"
#else
#define FRAMEBUFFER "/dev/graphics/fb0"
#define OUT_DIR "/sdcard/"
#endif


struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
char *frameBuffer = 0;
#define SKIA_SCALE 0
//打印fb驱动中fix结构信息,注:在fb驱动加载后,fix结构不可被修改。
void printFixedInfo()
{
    printf("Fixed screen info:\n"
            "\tid: %s\n"
            "\tsmem_start: 0x%lx\n"
            "\tsmem_len: %d\n"
            "\ttype: %d\n"
            "\ttype_aux: %d\n"
            "\tvisual: %d\n"
            "\txpanstep: %d\n"
            "\typanstep: %d\n"
            "\tywrapstep: %d\n"
            "\tline_length: %d\n"
            "\tmmio_start: 0x%lx\n"
            "\tmmio_len: %d\n"
            "\taccel: %d\n"
            "\n", finfo.id, finfo.smem_start, finfo.smem_len, finfo.type,
            finfo.type_aux, finfo.visual, finfo.xpanstep, finfo.ypanstep,
            finfo.ywrapstep, finfo.line_length, finfo.mmio_start,
            finfo.mmio_len, finfo.accel);
}

//打印fb驱动中var结构信息,注:fb驱动加载后,var结构可根据实际需要被重置
void printVariableInfo()
{
    printf("Variable screen info:\n"
            "\txres: %d\n"
            "\tyres: %d\n"
            "\txres_virtual: %d\n"
            "\tyres_virtual: %d\n"
            "\tyoffset: %d\n"
            "\txoffset: %d\n"
            "\tbits_per_pixel: %d\n"
            "\tgrayscale: %d\n"
            "\tred: offset: -, length: -, msb_right: -\n"
            "\tgreen: offset: -, length: -, msb_right: -\n"
            "\tblue: offset: -, length: -, msb_right: -\n"
            "\ttransp: offset: -, length: -, msb_right: -\n"
            "\tnonstd: %d\n"
            "\tactivate: %d\n"
            "\theight: %d\n"
            "\twidth: %d\n"
            "\taccel_flags: 0x%x\n"
            "\tpixclock: %d\n"
            "\tleft_margin: %d\n"
            "\tright_margin: %d\n"
            "\tupper_margin: %d\n"
            "\tlower_margin: %d\n"
            "\thsync_len: %d\n"
            "\tvsync_len: %d\n"
            "\tsync: %d\n"
            "\tvmode: %d\n"
            "\n", vinfo.xres, vinfo.yres, vinfo.xres_virtual,
            vinfo.yres_virtual, vinfo.xoffset, vinfo.yoffset,
            vinfo.bits_per_pixel, vinfo.grayscale, vinfo.red.offset,
            vinfo.red.length, vinfo.red.msb_right, vinfo.green.offset,
            vinfo.green.length, vinfo.green.msb_right, vinfo.blue.offset,
            vinfo.blue.length, vinfo.blue.msb_right, vinfo.transp.offset,
            vinfo.transp.length, vinfo.transp.msb_right, vinfo.nonstd,
            vinfo.activate, vinfo.height, vinfo.width, vinfo.accel_flags,
            vinfo.pixclock, vinfo.left_margin, vinfo.right_margin,
            vinfo.upper_margin, vinfo.lower_margin, vinfo.hsync_len,
            vinfo.vsync_len, vinfo.sync, vinfo.vmode);
}

//画大小为width*height的同色矩阵,8alpha+8reds+8greens+8blues
void drawRect_rgb32(int x0, int y0, int width, int height, int color)
{
    const int bytesPerPixel = 4;
    const int stride = finfo.line_length / bytesPerPixel;

    int *dest = (int *) (frameBuffer) + (y0 + vinfo.yoffset) * stride
            + (x0 + vinfo.xoffset);

    int x, y;
    for (y = 0; y < height; ++y)
    {
        for (x = 0; x < width; ++x)
        {
            dest[x] = color;
        }
        dest += stride;
    }
}

//画大小为width*height的同色矩阵,5reds+6greens+5blues
void drawRect_rgb16(int x0, int y0, int width, int height, int color)
{
    const int bytesPerPixel = 2;
    const int stride = finfo.line_length / bytesPerPixel;
    const int red = (color & 0xff0000) >> (16 + 3);
    const int green = (color & 0xff00) >> (8 + 2);
    const int blue = (color & 0xff) >> 3;
    const short color16 = blue | (green << 5) | (red << (5 + 6));

    short *dest = (short *) (frameBuffer) + (y0 + vinfo.yoffset) * stride
            + (x0 + vinfo.xoffset);

    int x, y;
    for (y = 0; y < height; ++y)
    {
        for (x = 0; x < width; ++x)
        {
            dest[x] = color16;
        }
        dest += stride;
    }
}

//画大小为width*height的同色矩阵,5reds+5greens+5blues
void drawRect_rgb15(int x0, int y0, int width, int height, int color)
{
    const int bytesPerPixel = 2;
    const int stride = finfo.line_length / bytesPerPixel;
    const int red = (color & 0xff0000) >> (16 + 3);
    const int green = (color & 0xff00) >> (8 + 3);
    const int blue = (color & 0xff) >> 3;
    const short color15 = blue | (green << 5) | (red << (5 + 5)) | 0x8000;

    short *dest = (short *) (frameBuffer) + (y0 + vinfo.yoffset) * stride
            + (x0 + vinfo.xoffset);

    int x, y;
    for (y = 0; y < height; ++y)
    {
        for (x = 0; x < width; ++x)
        {
            dest[x] = color15;
        }
        dest += stride;
    }
}

void drawRect(int x0, int y0, int width, int height, int color)
{
    switch (vinfo.bits_per_pixel)
    {
    case 32:
        drawRect_rgb32(x0, y0, width, height, color);
        break;
    case 16:
        drawRect_rgb16(x0, y0, width, height, color);
        break;
    case 15:
        drawRect_rgb15(x0, y0, width, height, color);
        break;
    default:
        printf("Warning: drawRect() not implemented for color depth %i\n",
                vinfo.bits_per_pixel);
        break;
    }
}

#define PERFORMANCE_RUN_COUNT 5
void performSpeedTest(void *fb, int fbSize)
{
    int i, j, run;
    struct timeval startTime, endTime;
    unsigned long long results[PERFORMANCE_RUN_COUNT];
    unsigned long long average;
    unsigned int *testImage;

    unsigned int randData[17] =
    { 0x3A428472, 0x724B84D3, 0x26B898AB, 0x7D980E3C, 0x5345A084, 0x6779B66B,
            0x791EE4B4, 0x6E8EE3CC, 0x63AF504A, 0x18A21B33, 0x0E26EB73,
            0x022F708E, 0x1740F3B0, 0x7E2C699D, 0x0E8A570B, 0x5F2C22FB,
            0x6A742130 };

    printf("Frame Buffer Performance test...\n");
    for (run = 0; run < PERFORMANCE_RUN_COUNT; ++run)
    {

        testImage = (unsigned int *) malloc(fbSize);
        j = run;
        for (i = 0; i < (int) (fbSize / sizeof(int)); ++i)
        {
            testImage[i] = randData[j];
            j++;
            if (j >= 17)
                j = 0;
        }

        gettimeofday(&startTime, NULL);
        memcpy(fb, testImage, fbSize);
        gettimeofday(&endTime, NULL);

        long secsDiff = endTime.tv_sec - startTime.tv_sec;
        results[run] = secsDiff * 1000000
                + (endTime.tv_usec - startTime.tv_usec);

        free(testImage);
    }

    average = 0;
    for (i = 0; i < PERFORMANCE_RUN_COUNT; ++i)
        average += results[i];
    average = average / PERFORMANCE_RUN_COUNT;

    printf(" Average: %llu usecs\n", average);
    printf(" Bandwidth: %.03f MByte/Sec\n",
            (fbSize / 1048576.0) / ((double) average / 1000000.0));
    printf(" Max. FPS: %.03f fps\n\n", 1000000.0 / (double) average);

    memset(fb, 0, fbSize);
}
//图片解码 将图片解码到bitmap的内存中,然后可以填充到framebuffer中。
bool SkFileDecoder(SkBitmap* bitmap, const char srcPath[], int bits_per_pixel)
{
    SkFILEStream stream(srcPath);
    if (!stream.isValid())
    {
        printf("ERROR: bad filename <%s>\n", srcPath);
        return false;
    }

    stream.rewind();
    SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
    if (NULL == codec)
    {
        printf("ERROR: no codec found for <%s>\n", srcPath);
        return false;
    }
    SkBitmap::Config config;
    switch (bits_per_pixel)
    {
    case 32:
        config = SkBitmap::kARGB_8888_Config;
        break;
    case 16:
        config = SkBitmap::kRGB_565_Config;
        break;
    default:
        printf("Warning: drawRect() not implemented for color depth %i\n",
                bits_per_pixel);
        break;
    }
    SkAutoTDelete < SkImageDecoder > ad(codec);

#if SKIA_SCALE

    SkBitmap tmp_bitmap;
    stream.rewind();
    if (!codec->decode(&stream, &tmp_bitmap, config ,
                    SkImageDecoder::kDecodeBounds_Mode))
    {
        printf("ERROR: codec failed for <%s>\n", srcPath);
        return false;
    }

    int maxpix = (tmp_bitmap.width() > tmp_bitmap.height()) ? tmp_bitmap.width():tmp_bitmap.width();
    int minpix = (tmp_bitmap.width() < tmp_bitmap.height()) ? tmp_bitmap.width():tmp_bitmap.width();
    int sample1 = maxpix/1028 + 1;
    int sample2 = maxpix/726 + 1;

    codec->setSampleSize(sample1>sample2 ? sample1:sample2);
#endif

    stream.rewind();
    if (!codec->decode(&stream, bitmap, config,
            SkImageDecoder::kDecodePixels_Mode))
    {
        printf("ERROR: codec failed for <%s>\n", srcPath);
        return false;
    }
    return true;
}

int main(int argc, char **argv)
{
    const char *devfile = FRAMEBUFFER;
    long int screensize = 0;
    int fbFd = 0;

    fbFd = open(devfile, O_RDWR);
    if (fbFd == -1)
    {
        perror("Error: cannot open framebuffer device");
        exit(1);
    }

    //获取finfo信息并显示
    if (ioctl(fbFd, FBIOGET_FSCREENINFO, &finfo) == -1)
    {
        perror("Error reading fixed information");
        exit(2);
    }
    printFixedInfo();
    //获取vinfo信息并显示
    if (ioctl(fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1)
    {
        perror("Error reading variable information");
        exit(3);
    }
    printVariableInfo();

    screensize = finfo.smem_len;

    frameBuffer = (char *) mmap(0, screensize, PROT_READ | PROT_WRITE,
            MAP_SHARED, fbFd, 0);
    if (frameBuffer == MAP_FAILED )
    {
        perror("Error: Failed to map framebuffer device to memory");
        exit(4);
    }

    //测试virt fb的性能
    performSpeedTest(frameBuffer, screensize);
    memset(frameBuffer, 0, screensize);

    printf("Will draw 3 rectangles on the screen,\n"
            "they should be colored red, green and blue (in that order).\n");
    drawRect(vinfo.xres / 8, vinfo.yres / 8, vinfo.xres / 4, vinfo.yres / 4,
            0xffff0000);
    drawRect(vinfo.xres * 3 / 8, vinfo.yres * 3 / 8, vinfo.xres / 4,
            vinfo.yres / 4, 0xff00ff00);
    drawRect(vinfo.xres * 5 / 8, vinfo.yres * 5 / 8, vinfo.xres / 4,
            vinfo.yres / 4, 0xff0000ff);

    sleep(5);
    printf(" Done.\n");
    memset(frameBuffer, 0, screensize);

    SkBitmap::Config config;
    switch (vinfo.bits_per_pixel)
    {
    case 32:
        config = SkBitmap::kARGB_8888_Config;
        break;
    case 16:
        config = SkBitmap::kRGB_565_Config;
        break;
    default:
        break;
    }

    SkBitmap bitmap;
    bitmap.setConfig(config, vinfo.xres, vinfo.yres);
    bitmap.allocPixels();
    SkCanvas canvas(bitmap);
    SkRect r;
    SkColor color = 0;

    SkPaint paint;
    paint.setARGB(255, 255, 0, 0);
    paint.setStrokeWidth(4);

    canvas.drawPoint(80, 80, 0xffff0000);
    memcpy(frameBuffer, bitmap.getPixels(), screensize);
    sleep(1);

    bitmap.eraseColor(0);
    SkIRect rect
    { 100, 100, 300, 300 };
    canvas.drawIRect(rect, paint);
    memcpy(frameBuffer, bitmap.getPixels(), screensize);
    sleep(1);

    bitmap.eraseColor(0);
    canvas.drawCircle(400, 300, 50, paint);
    memcpy(frameBuffer, bitmap.getPixels(), screensize);
    sleep(1);

    bitmap.eraseColor(0);
    canvas.drawLine(160, 10, 320, 110, paint);
    memcpy(frameBuffer, bitmap.getPixels(), screensize);
    sleep(1);
    bitmap.eraseColor(0);
    paint.setARGB(255, 255, 0, 0);
    canvas.drawCircle(400, 300, 200, paint);
    paint.setARGB(255, 255, 0, 155);
    canvas.drawCircle(400, 300, 195, paint);
    paint.setARGB(255, 0, 255, 255);
    canvas.drawLine(220, 300, 400, 300, paint);
    memcpy(frameBuffer, bitmap.getPixels(), screensize);

    for (int i = 0; i <= 0xffffffff; i++)
    {
        bitmap.eraseColor(0);
        SkBitmap Ibitmap;
        char name[32] = "";
        snprintf(name, sizeof(name), "/sdcard/%d.png", i % 7);
        SkFileDecoder(&Ibitmap, name, vinfo.bits_per_pixel);

        SkIRect src
        { 0, 0, bitmap.width(), bitmap.height() };
        SkRect dst
        { 0, 0, Ibitmap.width(), bitmap.height() };
        canvas.drawBitmapRect(Ibitmap, &src, dst);
        //SkScalar degree = 0;
        //SkScalar scal = 1;
        //SkScalar x = bitmap.width();
        //SkScalar y = bitmap.height();
        memcpy(frameBuffer, bitmap.getPixels(), screensize);
        sleep(2);
    }
    munmap(frameBuffer, screensize);    //解除内存映射,与mmap对应
    close(fbFd);
    return 0;
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

袁保康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值