- UID
- 824598
|
最近有个朋友希望我帮忙给他的一块板子加一个启动画面。板子是用烂了的三星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];
} |
|