前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >minigui 3.2.0:直接访问framebuffer的方法及示例

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

作者头像
10km
发布2019-05-25 20:29:55
1.6K0
发布2019-05-25 20:29:55
举报
文章被收录于专栏:10km的专栏10km的专栏

在做嵌入式应用程序开发时,有的场景下因为要追求图像显示效率,需要直接访问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,如下(请关注本文作者添加了中文注释的字段)

代码语言:javascript
复制
/* 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这个头文件,如下:

代码语言:javascript
复制
/*
 * 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的简单示例

代码语言:javascript
复制
#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);
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年10月30日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档