minigui 3.2.0:直接访问framebuffer的方法及示例

版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/83550368

在做嵌入式应用程序开发时,有的场景下因为要追求图像显示效率,需要直接访问Frame Buffer,比如更流畅的视频显示。基于minigui框架的应用程序该如何访问Frame Buffer呢?
最近就在为这个事儿头疼, 之前在设计时,视频输出是将一帧图像解码为BITMAP后作为窗口的背景画到屏幕上,这在PC模拟器上跑没啥问题,等到直接上开发板跑的时候,问题就来了----太慢。毕竟通过minigui这个框架要把一个BITMAP刷到屏幕上要经过好多个环节。所以肯定不如直接写Frame Buffer来得快呀。

于是就在想如何在MiniGUI的框架下直接读写Frame Buffer呢,翻遍了minigui公开的接口函数,没有提供这种直接读写Frame Buffer的方法。
不死心,在minigui源码中从BitBlt函数的实现代码开始一层层往下查。又倒过来从fbcon图形引擎的实现代码向上查。最终找到了GAL_Surface这个结构,这是NEWGAL的一个数据结构,定义在libminigui-3.2.0/src/include/newgal.h,如下(请关注本文作者添加了中文注释的字段)

/* This structure should be treated as read-only, except for 'pixels',
   which, if not NULL, contains the raw pixel data for the surface.
*/
typedef struct GAL_Surface {
    Uint32 flags;                       /* Read-only */
    GAL_PixelFormat *format;            /* 描述FrameBuffer的像素格式(RGB24,RGB565)的数据结构 */
    void *video;                        /* Read-only */
    int w, h;                           /* FrameBuffer宽高(像素) */
    /* VW[2018-01-18]: For 64b, use signed int instead of Uint32 for pitch. */
    int pitch;                          /* 每行像素的长度(字节) */
    void *pixels;                       /* FrameBuffer的起始地址 */
    int offset;                         /* Private */

    /* Hardware-specific surface info */
    struct private_hwdata *hwdata;

    /* clipping information */
    GAL_Rect clip_rect;                 /* Read-only */

    /* info for fast blit mapping to other surfaces */
    struct GAL_BlitMap *map;             /* Private */

    /* format version, bumped at every change to invalidate blit maps */
    unsigned int format_version;        /* Private */

    /* Reference count -- used when freeing surface */
    int refcount;                       /* Read-mostly */
} GAL_Surface;

不管结构中的其他字段,有了上面这个对象所提供的Frame Buffer的宽高(w,h),起始地址(pixels),行步长(pitch)信息,像素格式(GAL_PixelFormat 结构中的BitsPerPixel,BytesPerPixel字段),已经可以直接操作Frame Buffer了.

那么如何获取当前图形引擎的GAL_Surface 对象呢?还是要看libminigui-3.2.0/src/include/newgal.h这个头文件,如下:

/*
 * This function returns a pointer to the current display surface.
 * If GAL is doing format conversion on the display surface, this
 * function returns the publicly visible surface, not the real video
 * surface.
 */
extern GAL_Surface * GAL_GetVideoSurface (void);

好了,有了GAL_GetVideoSurface函数可以得到GAL_Surface, 但你会发现 libminigui-3.2.0/src/include/newgal.h这个头文件并没有出现在MiniGUI的release清单中,是未公开的。所以要把这个头文件复制到自己的项目中才能引用其中的函数。(记得要把newgal.h中的#include "gdi.h"改为#include <minigui/gdi.h>,否则编译通不过)
下面是关于从GAL_Surface直接访问Frame Buffer的简单示例

#include <string.h>
#include "newgal.h"
/**
 * 图像顺时针旋转90度并缩放到目标BITMAP的尺寸
 * @param src 原图像
 * @param [out] dst 缩放旋转后的图像
 */
static void scaledBitmap_Rotate90 (const PBITMAP src,PBITMAP dst)
{
	uint8_t* dst_line=  dst->bmBits;
	uint32_t sx,sy,st;
	uint8_t* spixel;
	// x,y缩放比例
	float ratex = (float)src->bmHeight/dst->bmWidth,ratey = (float)src->bmWidth/dst->bmHeight;
	for(int dy=0; dy < dst->bmHeight; ++dy)
	{
		for(int dx=0; dx < dst->bmWidth; ++dx)
		{
			// 坐标缩放
			sx = (uint32_t)(int)(dx * ratex),sy = (uint32_t)(int)(dy * ratey);
			// 坐标旋转
			st = sx,sx = sy,sy= src->bmHeight - st;
			// 目标像素的原始图像中的位置
			spixel = src->bmBits + sy*src->bmPitch + sx*src->bmBytesPerPixel;
			switch(dst->bmBytesPerPixel)
			{
			case 1:
				*(dst_line +dx) = *spixel;
				break;
			case 2:
				*((uint16_t*)(dst_line + dx*dst->bmBytesPerPixel)) = *((uint16_t*)spixel);
				break;
			case 4:
				*((uint32_t*)(dst_line + dx*dst->bmBytesPerPixel)) = *((uint32_t*)spixel);
				break;
			case 3:
			default:
				memcpy(dst_line+dx*dst->bmBytesPerPixel,spixel,dst->bmBytesPerPixel);
				break;
			}

		}
		dst_line += dst->bmPitch;
	}
}
void test()
{
	// 指向 frame buffer的 BITMAP
	BITMAP fb_bmp;
	// 获取当前图像引擎的GAL_Surface对象
	GAL_Surface* sf = GAL_GetVideoSurface();
	printf("GAL_Surface:%d x %d,BitsPerPixel %d,pitch %d",
			sf->w,sf->h,sf->format->BitsPerPixel,sf->pitch);
	// 根据GAL_Surface的参数将fb_bmp初始化为一个映射到FrameBuffer的BITMAP.
	if(!InitBitmap(HDC_SCREEN,sf->w,sf->h,sf->pitch,(BYTE*)sf->pixels,&fb_bmp))
	{
		printf("InitBitmap fail :%dx%d",sf->w,sf->h);
		return ;
	}
	// 将要显示的图像pbmp直接输出到frame buffer
	// 这个只是示例,你可以向代表frame buffer的fb_bmp写入任何数据,都会直接在屏幕显示
	scaledBitmap_Rotate90 (pbmp,&fb_bmp);
}


展开阅读全文

没有更多推荐了,返回首页