首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

在boot loader中加入启动画面及插值算法

在boot loader中加入启动画面及插值算法

最近有个朋友希望我帮忙给他的一块板子加一个启动画面。板子是用烂了的三星2410处理器。 不同之处就在于他的板子是640 x 480 VGA输出,而不是通常的240 x 320的LCD。

在Windows CE中,通常加入启动画面的方法很土,因为OS没有启动,所以没有什么BitBlt,StretchBlt等方法可以贴图,唯一的方法就是在启动的过程中,直接往显卡的Framebuffer里面写数据。这个工作一般在Boot Loader里面做,如果在OS启动的时候一般就太晚了,如果不加入人为的延时,启动画面刚一显示,就到了OS画面了。做法一般是这样,在Boot Loader里面:

BOOL OEMPlatformInit()
{
…………………………
   
   
    // Init the Display
    InitDisplay();

…………………………
}

然后是InitDisplay函数一般如下所示:
static void InitDisplay()
{
    int i = 0;
int j = 0;
    volatile IOPreg *s2410IOP;
    volatile LCDreg *s2410LCD;

    s2410IOP = (IOPreg *)IOP_BASE;
    s2410LCD = (LCDreg *)LCD_BASE;

    // LCD port initialize.
    s2410IOP->rGPCUP  = 0xFFFFFFFF;
    s2410IOP->rGPCCON = 0xAAAAAAAA;
    s2410IOP->rGPCCON = 0xAAAAAAAA;

    s2410IOP->rGPDUP  = 0xFFFFFFFF;
    s2410IOP->rGPDCON = 0xAAAAAAAA;

    s2410IOP->rGPGCON &= ~(3 << 8);                 /* Set LCD_PWREN as output                          */
    s2410IOP->rGPGCON |=  (1 << 8);

    s2410IOP->rGPGDAT |=  (1 << 4);                 /* Backlight ON                                     */


s2410LCD->rLCDCON1=(1<<8)|(MVAL_USED<<7)|(3<<5)|(12<<1)|0;
        // TFT LCD panel,16bpp TFT,ENVID=off
s2410LCD->rLCDCON2=(VBPD<<24)|(LINEVAL_TFT<<14)|(VFPD<<6)|(VSPW);
s2410LCD->rLCDCON3=(HBPD<<19)|(HOZVAL_TFT<<8)|(HFPD);
s2410LCD->rLCDCON4=(MVAL<<8)|(HSPW);
s2410LCD->rLCDCON5=(1<<11)|(1<<9)|(1<<8)|(1<<3)|(1<<0); //FRM5:6:5,HSYNC and VSYNC are inverted
s2410LCD->rLCDSADDR1=((FRAMEBUF_DMA_BASE>>22)<<21)|M5D(FRAMEBUF_DMA_BASE>>1);
s2410LCD->rLCDSADDR2=M5D( (FRAMEBUF_DMA_BASE+(LCD_XSIZE_TFT*LCD_YSIZE_TFT*2))>>1 );
s2410LCD->rLCDSADDR3=(((LCD_XSIZE_TFT-LCD_XSIZE_TFT)/1)<<11)|(LCD_XSIZE_TFT/1);
//s2410LCD->rLCDINTMSK|=(3); // MASK LCD Sub Interrupt
s2410LCD->rLPCSEL&=(~7); // Disable LPC3600
s2410LCD->rTPAL=0; // Disable Temp Palette

s2410LCD->rLCDCON1 |= 1;


// Display a bitmap image on the LCD...
    //memcpy((void *)FRAMEBUF_BASE, ScreenBitmap, ARRAY_SIZE_TFT_16BIT);

// Jason : Interpolation

EdbgOutputDebugString("+Interpolation\r\n");

for(i = 0; i < 320 * 240; i++)
{
  PWORD pWord = (PWORD)ScreenBitmap;
  PWORD pFrmBuf = (PWORD)FRAMEBUF_BASE;

  pFrmBuf[4 * i - 2 * (i % 320)] = pWord[i];
  pFrmBuf[4 * i - 2 * (i % 320) + 1] = pWord[i];
  pFrmBuf[4 * i - 2 * (i % 320) + 320 * 2] = pWord[i];
  pFrmBuf[4 * i - 2 * (i % 320) + 1 + 320 * 2] = pWord[i];


}

前面初始化硬件的代码没什么好看的。
注意到memcpy((void *)FRAMEBUF_BASE, ScreenBitmap, ARRAY_SIZE_TFT_16BIT);这一句,这就是显示启动画面的关键了,直接调用memcpy函数,把一个大数组,复制到了FRAMEBUF_BASE这个地址。这个其实就是直接往显卡缓冲区里面填东西了。至于这个大数组,可以用Image2LCD等类似软件生成,也就是直接把一张位图转成C语言数组的软件,这东西在游戏开发中用的比较多。

一般情况下,这种方法都是OK的,但是现在遇到什么问题呢?

因为目标设备的显示分辨率是640 x 480 x 16位的,所以这个大数组需要多大的存储空间是可以算出来的:640 * 480 * 2 = 600KB。但是对于一般的boot loader而言,板子上不会划分这么大的空间给boot loader用,一般boot loader的空间只有256KB。(其实可以人为改,只不过这个板子用linux的loader 引导CE的loader,才产生这么多问题)。所以解决方法只能有下面两条:

1. 压缩,然后在运行时候解压缩,然后再memcpy。可以找一些最基本的通用开源压缩算法来完成。
2. 插值,弄一张小图片,把它插值到640 x 480。

两者权衡,偶还是决定采用插值的办法,这样的工作量还是小一些的。其实也就是自己把StretchBlt函数实现了。

哎,本科的时候没有开设图形学,所以也不知道插值有没有具体的公式,只能自己推导了。好在这个不是一个通用的算法,只是放大4倍的这样一个特例。一个点变四个点,还是很容易的。自己拿着纸笔比划了一阵子,终于得出个公式来,公式不好帖,直接帖代码就是下面这样:

for(i = 0; i < 320 * 240; i++)
{
  PWORD pWord = (PWORD)ScreenBitmap;
  PWORD pFrmBuf = (PWORD)FRAMEBUF_BASE;

  pFrmBuf[4 * i - 2 * (i % 320)] = pWord[i];
  pFrmBuf[4 * i - 2 * (i % 320) + 1] = pWord[i];
  pFrmBuf[4 * i - 2 * (i % 320) + 320 * 2] = pWord[i];
  pFrmBuf[4 * i - 2 * (i % 320) + 1 + 320 * 2] = pWord[i];
}
返回列表