[自制操作系统] BMP格式文件读取&图形界面系统框架/应用接口设计

本文介绍了作者在自制操作系统中实现BMP格式文件读取及图形界面系统框架的设计,涉及framebuffer、双缓冲、图像处理问题、调色板管理以及图形界面应用程序接口。通过案例分享了读取BMP文件头、颜色处理、屏幕刷新等问题的解决方法,并展示了日历和系统信息等应用的实现。
摘要由CSDN通过智能技术生成

这里写图片描述

本文将介绍在本人JOS中实现的简单图形界面应用程序接口,应用程序启动器,以及一些利用了图形界面的示例应用程序。

Github : https://github.com/He11oLiu/MOS
演示视频:优酷视频

本文主要涉及以下部分:

  • 内核/用户RW/RW调色板framebuffer共享区域
  • 8bit颜色深度BMP格式图片读取与绘制
    • BMP头总是出现问题?不合理的数据?
    • 为啥读出来的图片颜色怪怪的!!
    • 为啥是倒的,还有的运气不好出错了
    • 如果是想绘制多个图片在一页上,调色板问题??
    • 如果读到一个32位色的图片咋办?
  • 图形化界面数据结构,框架以及接口设计
  • 利用图形化接口实现应用程序:
    • 日历程序(实时时钟刷新)
    • 系统信息获取
    • 终端CGA模拟器

PART1

framebuffer

图形库中,已经将图形模式打开,将显存映射到内存中的一段空间。并进行了简单的测试。

实际上,直接对显存写是很不负责任的行为。很早之前在写java的界面的时候,就接触了双缓冲技术,其实与显示有关的思想都是差不多的,我们应该提供一个framebuffer。当完成一个frame后,再将这个frame update到显存中。

uint8_t *framebuffer;
void init_framebuffer(){
    if((framebuffer = (uint8_t *) kmalloc((size_t)(graph.scrnx*graph.scrny)))== NULL)
        panic("Not enough memory for framebuffer!");
}

void update_screen(){
    memcpy(graph.vram,framebuffer,graph.scrnx*graph.scrny);
}

经过实现kmallockfree,已经可以分配这个缓冲区,并直接向缓冲区写入,最后再进行update

#define PIXEL(x, y) *(framebuffer + x + (y * graph.scrnx))
int draw_xx()
{
    xxx;
    update_screen();
}

canvas (这种思路已经废弃)

从一个单一的应用程序角度来看,应分配一个单独的画布,然后选择在一个位置显示。

typedef struct canvas
{
    uint16_t width;
    uint16_t height;
    uint8_t *data;
} canvas_t;

设计的模式是,与文件系统服务器类似,提供一个图形系统服务器,用于接收从其他的程序发来的请求。请求包括显示的位置,以及canvas。该服务器将canvas写入frambuffer并update。其他程序与图形服务器通过IPC进行通讯。

剩余的事情就可以交给用户空间了。包括对canvas的处理,更新显示,添加各种元件。之前写的字库也可以不用写在内核了…

首先实现绘制canvas

int draw_canvas(uint16_t x, uint16_t y, canvas_t *canvas)
{
    int i, j;
    int width = (x + canvas->width) > graph.scrnx ? graph.scrnx : (x + canvas->width);
    int height = (y + canvas->height) > graph.scrny ? graph.scrny : (y + canvas->height);
    cprintf("width %d height %d\n",width,height);
    for (j = y; j < height; j++)
        for (i = x; i < width; i++)
            PIXEL(i, j) = *(canvas->data + (i - x) + (j - y) * canvas->width);
    update_screen();
    return 0;
}

然后在lib中新建canvas的相关方法:

int canvas_init(uint16_t width, uint16_t height, canvas_t *canvas);
int canvas_draw_bg(uint8_t color, canvas_t *canvas);
int canvas_draw_ascii(uint16_t x, uint16_t y, char *str, uint8_t color, canvas_t *canvas);
int canvas_draw_cn(uint16_t x, uint16_t y, char *str, uint8_t color, canvas_t *canvas);
int canvas_draw_rect(uint16_t x, uint16_t y, uint16_t l, uint16_t w, uint8_t color, canvas_t *canvas);

其中只需要将原来的PIXAL宏换为

#define CANVAS_PIXEL(canvas, x, y) *(canvas->data + x + (y * canvas->width))

测试canvas

    canvas_t canvas_test;
    canvas_init(300, 200, &canvas_test);
    uint8_t testcanvas[60000];
    canvas_test.data = (uint8_t *)testcanvas;
    canvas_draw_bg(0x22,&canvas_test);
    canvas_draw_ascii((uint16_t)2, (uint16_t)2, test_ascii, (uint8_t)0xff, &canvas_test);
    canvas_draw_cn((uint16_t)2, (uint16_t)50, test_cn, (uint8_t)0xff, &canvas_test);
    draw_canvas(500, 500, &canvas_test);

图像处理的两种设计与遇到的问题

  • 第一种设计与之前描述的一致:

    提供一个图像服务器,接收请求,从用户进程传来需要画的画布和显示位置,并在位置上进行绘画。这种方式遇到的问题是画布过大,一页可能装不下。需要mmap(还没写)

  • 第二种设计是一个launcherapplication两个单独的单页面切换制度。

    这样就是launcher提供应用启动界面,application提供应用界面。

重新回顾了一下内存分配,内核与用户态数据共享的方法后,决定先就第二个思路实现一个简单的用户内核均可见可读写的Framebuffer

实现RW/RWFramebuffer

分析如何做才能内核用户均可读写

首先分析一个之前做过的pages,是如何做到用户态可以读,内核态可以写的。

  • mem_init的时候在在内核空间中分配指定的空间给pages

    pages = boot_alloc(sizeof(struct PageInfo) * npages);
    memset(pages, 0, sizeof(struct PageInfo) * npages);
  • 利用boot_map_region将其映射到内核页表中的UPAGES的位置。

    boot_map_region(kern_pgdir, UPAGES, PTSIZE, PADDR(pages), PTE_U | PTE_P);
  • 这样内核中依然可以通过pages访问页表,而用户程序在entry的时候通过给pages变量赋予存储位置

    .globl pages
    .set pages, UPAGES

    也可以通过pages变量进行访问。

预留内存用于framebuffer

再思考如果需要这么一个framebuffer,我们需要放到哪里。仿造上面的UVPDUPAGES,等,决定就放在接近ULIM的位置。一个PTSIZE也远超我们需要的空间,为以后扩展也留下了余量。

/*
 * ULIM, MMIOBASE -->  +------------------------------+ 0xef800000
 *                     |  Cur. Page Table (User R-)   | R-/R-  PTSIZE
 *    UVPT      ---->  +------------------------------+ 0xef400000
 *                     |          RO PAGES            | R-/R-  PTSIZE
 *  FRAMEBUF    ---->  +------------------------------+ 0xef000000
 *                     |        FRAME BUFFER          | RW/RW  PTSIZE
 *    UPAGES    ---->  +------------------------------+ 0xeec00000
 *                     |           RO ENVS            | R-/R-  PTSIZE
 * UTOP,UENVS ------>  +-----------------------------
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值