minigui相关硬件加速添加方法

一、关于硬件加速

1.1 介绍

以海思平台的TDE加速显示模块为例,它主要为OSD和GUI提供快速的图形绘制功能,主要有快速位图搬移,快速色彩填充,快速抗闪搬移、快速位图缩放,画点、画水平/垂直线、位图格式转换,位图alpha叠加,位图按布尔值运算、ColorKey等操作。

1.2 应用

如何在minigui上应用这些加速模块呢?
上一章详解minigui图片加载及显示介绍了从图片解码装载到bitmap,再由bitmap刷新到fb的整个大体流程。所有图片刷新或者window刷新都离不开后面刷新到fb的流程。可以看到2.2显示过程中的最后调用的是GAL_UpdateRect其实这里就封装了硬件快速位图搬移的操作接口。
minigui上提供了newgal(graphic abstract layer)硬件抽象层。也就是该层提供了所有硬件操作的方法接口。那么只要实现GAL_VideoDevice这个结构体句柄就可以在调用GAL_UpdateRect时调用到device->UpdateRects = MStar_DirectUpdate;具体硬件的位图搬移。

二、主要的接口实现

下面为minigui较为常用的硬件加速接口

struct GAL_VideoDevice {
	int (*VideoInit)(_THIS, GAL_PixelFormat *vformat); //平台相关FB的硬件初始化函数
	GAL_Surface *(*SetVideoMode)(_THIS, GAL_Surface *current,
				int width, int height, int bpp, Uint32 flags); //这个可以认为是系统surface可以直接与FB相绑定也可以自己虚拟一个给他,这个是导入到系统使用的也就是bitblt最终会搬移到这个surface上
	void (*UpdateRects)(_THIS, int numrects, GAL_Rect *rects); //快速位图搬移,应用于区域图形更新可以是一个window也可以是一个图标
	int (*AllocHWSurface)(_THIS, GAL_Surface *surface); //为硬件操作分配dma或者其他特定连续内存
	int (*CheckHWBlit)(_THIS, GAL_Surface *src, GAL_Surface *dst); // 查询硬件是否提供了快速位图搬移操作接口,即是否实现了下面的GAL_blit硬件操作接口函数将其返回给surface src的src->map->hw_blit = MStar_HWAccelBlit;
	int (*FillHWRect)(_THIS, GAL_Surface *dst, GAL_Rect *rect, Uint32 color);//快速色彩填充
	int (*SetHWColorKey)(_THIS, GAL_Surface *surface, Uint32 key); //ColorKey操作
	int (*SetHWAlpha)(_THIS, GAL_Surface *surface, Uint8 value); //位图alpha叠加
	void (*FreeHWSurface)(_THIS, GAL_Surface *surface); //释放AllocHWSurface分配的存储空间
	}
	//以及GAL_Surface GAL_BlitMap的私有快速位图搬运接口
	typedef int (*GAL_blit)(struct GAL_Surface *src, GAL_Rect *srcrect,
                        struct GAL_Surface *dst, GAL_Rect *dstrect);
  //该接口是private DC或者window second DC所私有的surface的快速位图搬运接口。后面会说明不同dc的位图刷新过程。

不同的硬件平台有各自不同的TDE加速模块。所以具体的实现就不说明了。需要读者根据不同平台去做适配,但是适配之前你需要明白这些接口是做什么用的,还有什么时候才会调用到这些接口。

三、何时会调用到这些加速接口

上一篇文章详解minigui图片加载及显示只提到了什么时候会调用到device->UpdateRects,也就是可以调用FillBoxWithBitmap就可以使用到快速图形搬移了。试想如果你整个UI都使用FillBoxWithBitmap 来画那将会在视觉上看到图标是一个个贴出来的。这样就显得不流畅自然。所以我们可以借助minigui给我们的window DC来先画好一整个window子窗口再将其通过 UpdateRects 的方式贴合到FB上。具体的流程如下:

3.1 应用层:

创建一个dialogbox

static DLGTEMPLATE DlgInitProgress =
{
    WS_BORDER | WS_CAPTION, 
    WS_EX_AUTOSECONDARYDC,
    120, 150, 400, 140, 
    the_system_is_initializing,
    0, 0,
    3, NULL,
    0
};

static CTRLDATA CtrlInitProgress [] =
{ 
    {
        "button",
        WS_TABSTOP | WS_VISIBLE | BS_DEFPUSHBUTTON, 
        170, 70, 60, 25,
        IDOK, 
        OK,
        0
    }
};

static int InitDialogBoxProc (HWND hDlg, int message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
    case MSG_INITDIALOG:
        return 1;       
    case MSG_COMMAND:
        switch (wParam) {
        case IDOK:
        case IDCANCEL:
            EndDialog (hDlg, wParam);
            break;
        }
        break;
    case MSG_PAINT:
    			 //画多个图标到secondary DC 
    		   hdc = BeginPaint (hWnd);
            FillBoxWithBitmap (hdc, 0, 0, 100, 100, &bmp);
            Rectangle (hdc, 0, 0, 100, 100);
            FillBoxWithBitmap (hdc, 100, 0, 200, 200, &bmp);
            Rectangle (hdc, 100, 0, 300, 200);
            FillBoxWithBitmapPart (hdc, 0, 200, 150, 150, 200, 200, &bmp, 10, 10);
            Rectangle (hdc, 0, 200, 400, 400);
            EndPaint (hWnd, hdc);
    		break;
    case MSG_CLOSE:
        EndDialog (hDlg, IDCANCEL);
        break;
    }
    return DefaultDialogProc (hDlg, message, wParam, lParam);
}

static void InitDialogBox (HWND hWnd)
{
    DlgInitProgress.controls = CtrlInitProgress;
    DialogBoxIndirectParam (&DlgInitProgress, hWnd, InitDialogBoxProc, 0L);
}

int MiniGUIMain (int argc, const char* argv[])
{
#ifdef _MGRM_PROCESSES
    JoinLayer(NAME_DEF_LAYER , "dialogbox" , 0 , 0);
#endif
    InitDialogBox (HWND_DESKTOP);
    return 0;
}
#ifdef _MGRM_THREADS
#include <minigui/dti.c>
#endif

你可以在这个dialogbox上用 FillBoxWithBitmap 来画你的背景图或者图标,但是前提是这个dialog的DLGTEMPLATE 模板 的属性必须得是WS_EX_AUTOSECONDARYDC /*The window creates its own secondary device context automatically.*/ 这样dialog就会自动创建一个子DC,子DC的surface就是该窗口画图的层画完之后调用EndPaint 就会再调用到UpdateRects去更新该窗口到FB,这时候就是整块刷了,不会看到一个个小图标渐次出来。
具体的流程如下图所示
在这里插入图片描述middle layer就是minigui所谓的双buffer,这样在画图的时候就是转到后台操作了,故在画图的时候显示不会出现闪烁的情况。可以看到箭头处三个关键函数GAL_PutBox GAL_blit UpdateRects 作用分别是:
GAL_PutBox 是软件算法函数用于将FillBoxWithBitmap填充进来的icon bitmap画到预先malloc的dc mem上,当画好整个页面后EndPaint会将window rect通过bitblt GAL_Blit画到中间图层,接着在bitblt的最后调用UpdateRects画到最终的图层,这个流程可以简化到将updateRects的操作搬移到GAL_blit上从而减少拷贝次数,后面的updateRects有点没必要了(前提是你用的是单buffer)。详细流程看上图。
如果你使用的realbuffer是双buffer那么还是用使用上次流程图。在updateRect的时候先更新到后台buffer再切换buffer显示,再更新到之前使用的buffer,保存双buffer上的内容的一致性。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值