问题描述
最近遇到一个framebuffer是RGB565(16bpp),minigui显示不正常的问题,显示现象如下
原始图片
屏幕上显示的效果
然后直接显示红绿蓝三色的图片
在屏幕上显示的效果
在RGB565中
颜色 | 值 |
---|---|
RED | 0xF800 |
GREEN | 0x07E0 |
BLUE | 0x001F |
分析原因发现是和LCD有关,在发送RGB数据的时候,驱动发送R分量是发送0x00F8,G分量0xE007,B分量0x1F00,也就是说大小端进行了交换,所以需要把源数据的像素值的大小端进行交换
解决方法
主要是LoadBitmapFromFile加载图片函数,FillBoxWithBitmap填充图片函数
//libminigui-gpl-3.2/src/newgdi/readbmp.c //图片加载函数 int GUIAPI LoadBitmapEx (HDC hdc, PBITMAP bmp, MG_RWops* area, const char* ext) { //... ret = LoadMyBitmapSL (area, load_info, &my_bmp, cb_load_bitmap_sl, &info); //判断是16bpp的并且图片不带alpha的时候才进行转换,因为带透明的图在alpha blend的时候会出现blend颜色不对的现象 if (!(bmp->bmType & BMP_TYPE_ALPHA) && bmp->bmBitsPerPixel == 16) { int x, y; Uint16 *srcrow = (Uint16 *) bmp->bmBits; //循环遍历每一个像素点 for (y = bmp->bmHeight; y; --y) { for (x = bmp->bmWidth; x; --x) { //大小端转换 *srcrow = ((*srcrow & 0xff00) >> 8) | ((*srcrow & 0xff) << 8); srcrow++; } } }
CleanupMyBitmapSL <span class="token punctuation">(</span><span class="token operator">&</span>my_bmp<span class="token punctuation">,</span> load_info<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> ret<span class="token punctuation">;</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
//libminigui-gpl-3.2/src/newgal/surface.c
//源带透明度的叠加函数
static int _PutBoxAlpha (GAL_Surface* dst, BYTE* dstrow, BYTE* srcrow, Uint32 w, Uint32 h, BITMAP* box)
{
//...
//循环BLEND每一个像素值
while ( h-- ) {
dstpixels = dstrow;
srcpixels = srcrow;
alpha_mask_index = alpha_mask_row;
DUFFS_LOOP(
{
Uint32 pixel;
unsigned sR;
unsigned sG;
unsigned sB;
unsigned sA;
unsigned dR;
unsigned dG;
unsigned dB;
//SRC带透明度的大小端没有转换,所以不需还原
DISEMBLE_RGB_ALPHA (srcpixels, bpp, dstfmt, pixel, sR, sG, sB);
//DST是经过大小端转换的,所以需要再还原
DISEMBLE_RGB (dstpixels, bpp, dstfmt, pixel, dR, dG, dB);
sA = box->bmAlphaMask[alpha_mask_index];
//只有还原的像素值才能正常BLEND
ALPHA_BLEND (sR, sG, sB, sA, dR, dG, dB);
//BLEND之后再进行大小端交换才能显示正常
ASSEMBLE_RGBA (dstpixels, bpp, dstfmt, dR, dG, dB, alpha);
dstpixels += bpp;
srcpixels += bpp;
alpha_mask_index++;
},
w);
srcrow += box->bmPitch;
dstrow += dst->pitch;
alpha_mask_row += alpha_mask_pitch;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
//SRC获取RGB分量
//libminigui-gpl-3.2/src/newgal/blit.h
#define DISEMBLE_RGB_ALPHA(buf, bpp, fmt, pixel, r, g, b) \
do { \
switch (bpp) { \
case 2: \
pixel = *((Uint16 *)(buf)); \
break; \
default: \
pixel = 0; /* prevent gcc from complaining */ \
break; \
} \
RGB_FROM_PIXEL(pixel, fmt, r, g, b); \
} while(0)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
//DST获取RGB分量
//libminigui-gpl-3.2/src/newgal/blit.h
#define DISEMBLE_RGB(buf, bpp, fmt, pixel, r, g, b) \
do { \
switch (bpp) { \
case 2: \
pixel = *((Uint16 *)(buf)); \
//把交换的大小端再还原
pixel = ((pixel & 0xff00) >> 8) | ((pixel & 0xff) << 8); \
break; \
default: \
pixel = 0; /* prevent gcc from complaining */ \
break; \
} \
RGB_FROM_PIXEL(pixel, fmt, r, g, b); \
} while(0)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
//libminigui-gpl-3.2/src/newgal/blit.h
//根据源alpha值混合两个像素的RGB值
#define ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB) \
do { \
dR = (((sR-dR)*(A))>>8)+dR; \
dG = (((sG-dG)*(A))>>8)+dG; \
dB = (((sB-dB)*(A))>>8)+dB; \
} while(0)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
//libminigui-gpl-3.2/src/newgal/blit.h
//把BLEND好的像素值写到buffer上
#define ASSEMBLE_RGBA(buf, bpp, fmt, r, g, b, a) \
{ \
switch (bpp) { \
case 2: { \
Uint16 pixel; \
PIXEL_FROM_RGBA(pixel, fmt, r, g, b, a); \
//把BLEND好的像素值大小端交换
pixel = ((pixel & 0xff00) >> 8) | ((pixel & 0xff) << 8); \
*((Uint16 *)(buf)) = pixel; \
} \
break; \
} \
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
还有一个填充矩形的函数FillBox,当然还有其他一些画线条的函数需要修改
//libminigui-gpl-3.2/src/newgal/surface.c
//填充颜色函数
int GAL_FillRect(GAL_Surface *dst, const GAL_Rect *dstrect, Uint32 color)
{
//...
switch (dst->format->BytesPerPixel) {
case 2:
//把颜色的大小端交换一下即可
color = ((color & 0xff00) >> 8) | ((color & 0xff) << 8);
for ( y=my_dstrect.h; y; --y ) {
Uint16 *pixels = (Uint16 *)row;
Uint16 c = color;
Uint32 cc = (Uint32)c << 16 | c;
int n = my_dstrect.w;
if((unsigned long)pixels & 3) {
*pixels++ = c;
n--;
}
if(n >> 1)
GAL_memset4(pixels, cc, n >> 1);
if(n & 1)
pixels[n - 1] = c;
row += dst->pitch;
}
break;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
还有一个好的方法,以上的修改全都不需要,直接修改获取颜色的掩码,交换Rmask、Gmask、Bmask的大小端,但是这种方法显示的颜色有点失真
//libminigui-gpl-3.2/src/newgal/fbcon/fbvideo.c
//设置fbcon引擎的一些配置
static GAL_Surface *FB_SetVideoMode(_THIS, GAL_Surface *current,
int width, int height, int bpp, Uint32 flags)
{
//...
Rmask = 0;
for ( i=0; i<vinfo.red.length; ++i ) {
Rmask <<= 1;
Rmask |= (0x00000001<<vinfo.red.offset);
}
Gmask = 0;
for ( i=0; i<vinfo.green.length; ++i ) {
Gmask <<= 1;
Gmask |= (0x00000001<<vinfo.green.offset);
}
Bmask = 0;
for ( i=0; i<vinfo.blue.length; ++i ) {
Bmask <<= 1;
Bmask |= (0x00000001<<vinfo.blue.offset);
}
Amask = 0;
for ( i=0; i<vinfo.transp.length; ++i ) {
Amask <<= 1;
Amask |= (0x00000001<<vinfo.transp.offset);
}
//这里交换
Rmask = ((Rmask & 0xff00) >> 8) | ((Rmask & 0xff) << 8);
Gmask = ((Gmask & 0xff00) >> 8) | ((Gmask & 0xff) << 8);
Bmask = ((Bmask & 0xff00) >> 8) | ((Bmask & 0xff) << 8);
Amask = ((Amask & 0xff00) >> 8) | ((Amask & 0xff) << 8);
}
static int FB_VideoInit(_THIS, GAL_PixelFormat *vformat)
{
//…
for ( i=0; i<vinfo.red.length; ++i ) {
vformat->Rmask <<= 1;
vformat->Rmask |= (0x00000001<<vinfo.red.offset);
}
for ( i=0; i<vinfo.green.length; ++i ) {
vformat->Gmask <<= 1;
vformat->Gmask |= (0x00000001<<vinfo.green.offset);
}
for ( i=0; i<vinfo.blue.length; ++i ) {
vformat->Bmask <<= 1;
vformat->Bmask |= (0x00000001<<vinfo.blue.offset);
}
for ( i=0; i<vinfo.transp.length; ++i ) {
vformat->Amask <<= 1;
vformat->Amask |= (0x00000001<<vinfo.transp.offset);
}
//这里交换
vformat->Rmask = ((vformat->Rmask & 0xff00) >> 8) | ((vformat->Rmask & 0xff) << 8);
vformat->Gmask = ((vformat->Gmask & 0xff00) >> 8) | ((vformat->Gmask & 0xff) << 8);
vformat->Bmask = ((vformat->Bmask & 0xff00) >> 8) | ((vformat->Bmask & 0xff) << 8);
vformat->Amask = ((vformat->Amask & 0xff00) >> 8) | ((vformat->Amask & 0xff) << 8);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
</div>
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-e44c3c0e64.css" rel="stylesheet">
</div>