一、引言
上一章 minigui相关硬件加速添加方法 介绍了从绘图到显示的整体流程,以及最终调用到的硬件加速方法。如果我们不用DC MEM的话那将是每一次FillBoxWithBitmap ,以及DrawText,settext都会是直接调用到硬件的updateRect直接画出来,可以看到icon以及字符是一个一个刷出来的,这个也可以在updaterect处加打印验证。为了避免这样的问题,我们使用DC mem可以在整个window画完后再调用updateRect将整个window更新到framebuffer。
这一章我们重点介绍私有以及DC mem绘制的过程,主要分析入口为上一章的dialog callback的print msg中绘图部分。如下:
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);
FillBoxWithBitmap (hdc, 100, 0, 200, 200, &bmp);
FillBoxWithBitmapPart (hdc, 0, 200, 150, 150, 200, 200, &bmp, 10, 10);
EndPaint (hWnd, hdc);
break;
}
留意咋们创建的dialog属性是WS_EX_AUTOSECONDARYDC,自动创建窗口子DC。
static DLGTEMPLATE DlgInitProgress =
{
WS_BORDER | WS_CAPTION,
WS_EX_AUTOSECONDARYDC,
120, 150, 400, 140,
the_system_is_initializing,
0, 0,
3, NULL,
0
};
二、流程分析
我们从创建dialog的接口DialogBoxIndirectParam开始分析
DialogBoxIndirectParam
DialogBoxIndirectParamEx
CreateMainWindowIndirectParamEx
CreateMainWindowEx
SendMessage (HWND_DESKTOP, MSG_ADDNEWMAINWIN, (WPARAM) pWin, 0)
WindowMessageHandler //desktop-comm.c 接收MSG_ADDNEWMAINWIN消息
case MSG_ADDNEWMAINWIN:
return dskAddNewMainWindow(pWin);
dskAddNewMainWindow
if (pWin->dwExStyle & WS_EX_AUTOSECONDARYDC) \\最后在这里创建窗口子dc
pWin->secondaryDC = CreateSecondaryDC ((HWND)pWin);
CreateSecondaryDC
CreateCompatibleDCEx //创建mem DC ,这个接口也是自己创建与fb相同属性的memory dc的接口
接着CreateCompatibleDCEx分析
CreateCompatibleDCEx
GAL_CreateRGBSurface
if ( ((flags&GAL_HWSURFACE) == GAL_SWSURFACE) ||
(video->AllocHWSurface(this, surface) < 0) ) //AllocHWSurface就是硬件加速的分配接口抽象
GAL_FreeSurface(surface);
video->FreeHWSurface(this, surface);//FreeHWSurface是释放硬件分配空间的接口
绘制过程分析:BeginPaint -> FillBoxWithBitmap -> EndPaint ;BeginPaint 的作用我们可以暂时理解为获取hdc句柄的作用。重点分析后面两个函数接口。参考上一篇文章 详解minigui图片加载及显示
分析icon贴图流程为何在mem dc的情况下不会调用updaterect更新到framebuffer。
FillBoxWithBitmap (HDC hdc, int x, int y, int w, int h, const BITMAP* bmp)
_begin_fill_bitmap (hdc, x, y, w, h, bmp, &fill_info); //计算填充区域信息
_fill_bitmap (pdc, bmp, &fill_info);
_dc_fillbox_bmp_clip (pdc, &fill_info->dst_rect, (BITMAP*)bmp); //不缩放的情况下调用该函数
GAL_PutBox (pdc->surface, rect, bmp); //开始填充
GAL_IntersectRect //计算重叠的填充区域 仅计算重绘的区域
dstrow = (Uint8 *)dst->pixels + my_dstrect.y * dst->pitch + my_dstrect.x * dst->format->BytesPerPixel; //目的framebuffer
srcrow = (Uint8 *)box->bmBits + off_y * box->bmPitch + off_x * box->bmBytesPerPixel; //源bitmap
_PutBoxAlpha (dst, dstrow, srcrow, w, h, box); //根据h高度一行行进行拷贝采用DUFFS_LOOP8拷贝
_end_fill_bitmap (pdc, bmp, &fill_info); //拷贝完成后更新到真实framebuffer进行显示
__mg_leave_drawing (pdc);
{if (!dc_IsMemDC (pdc))
kernel_ShowCursorForGDI (TRUE, pdc);} //这里这里的dc_IsMemDC (pdc)判断,如果是memory dc就不调用kernel_ShowCursorForGDI 进行updaterect刷新
GAL_UpdateRect (cur_pdc->surface, prc->left, prc->top, RECTWP(prc), RECTHP(prc)); //调用硬件tde 进行局部更新。
dc_IsMemDC 是关键原型为
static inline BOOL dc_IsMemDC (PDC pdc)
{
return (pdc->DCType == TYPE_MEMDC);
}
接着咱们分析EndPaint 该函数将会调用updateRect将mem dc刷新到framebuffer
EndPaint
if (pWin->pMainWin->secondaryDC) { //如果是secondary dc
if (!IsRectEmpty(&pWin->pMainWin->update_rc)) {
HDC real_dc = HDC_INVALID;
real_dc = GetClientDC ((HWND)pWin->pMainWin);
update_secondary_dc (pWin, hdc, real_dc,
&pWin->pMainWin->update_rc, HT_CLIENT);
BitBlt (secondary_dc, rc->left, rc->top, //最终调用到bitblt后面的调用就去查看上篇文章
RECTWP(rc), RECTHP(rc),
real_dc, clip_rc.left, clip_rc.top, 0);
三、 memory DC 主要接口
HDC GUIAPI CreateCompatibleDC (HDC hdc);
HDC GUIAPI CreateMemDC (int width, int height, int depth, DWORD flags,
Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
BOOL GUIAPI ConvertMemDC (HDC mem_dc, HDC ref_dc, DWORD flags);
BOOL GUIAPI SetMemDCAlpha (HDC mem_dc, DWORD flags, Uint8 alpha);
BOOL GUIAPI SetMemDCColorKey (HDC mem_dc, DWORD flags, Uint32 color_key);
void GUIAPI DeleteMemDC (HDC mem_dc);
定制自己的memory DC然后通过bitblt更新到主窗口的DC可以使用如下代码
/* 具有 Alpha 通道 的内存 DC:24位,RGB 各占 8 位,无 Alpha 分量 */
mem_dc = CreateMemDC (400, 100, 24, MEMDC_FLAG_HWSURFACE | MEMDC_FLAG_SRCALPHA | MEMDC_FLAG_SRCCOLORKEY,0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000);
/* 输出填充矩形和文本到内存 DC 上 */
SetBrushColor (mem_dc, RGB2Pixel (mem_dc, 0xFF, 0xFF, 0x00));
FillBox (mem_dc, 0, 0, 400, 100);
SetBkMode (mem_dc, BM_TRANSPARENT);
SetTextColor (mem_dc, RGB2Pixel (mem_dc, 0x00, 0x00, 0xFF));
TabbedTextOut (mem_dc, 0, 0, "Memory DC with alpha.\n"
"The source DC have alpha per-surface.");
/* Blit 到窗口 DC 上 */
start_tick = GetTickCount ();
count = 100;
while (count--) {
/* 设置内存 DC 的 Alpha 通道 */
SetMemDCAlpha (mem_dc, MEMDC_FLAG_SRCALPHA | MEMDC_FLAG_RLEACCEL, rand () % 256);
BitBlt (mem_dc, 0, 0, 400, 100, hdc, rand () % 800, rand () % 800);
}
end_tick = GetTickCount ();
TellSpeed (hwnd, start_tick, end_tick, "Alpha Blit", 100);
/* 填充矩形区域, 并输出文字 */
FillBox (mem_dc, 0, 0, 400, 100);
SetBrushColor (mem_dc, RGB2Pixel (mem_dc, 0xFF, 0x00, 0xFF));
TabbedTextOut (mem_dc, 0, 0, "Memory DC with alpha and colorkey.\n"
"The source DC have alpha per-surface.\n"
"And the source DC have a colorkey, \n"
"and RLE accelerated.");
/* 设置内存 DC 的透明象素值 */
SetMemDCColorKey (mem_dc, MEMDC_FLAG_SRCCOLORKEY | MEMDC_FLAG_RLEACCEL,
RGB2Pixel (mem_dc, 0xFF, 0xFF, 0x00));
/* Blit 到窗口 DC 上 */
start_tick = GetTickCount ();
count = 100;
while (count--) {
BitBlt (mem_dc, 0, 0, 400, 100, hdc, rand () % 800, rand () % 800);
CHECK_MSG;
}
end_tick = GetTickCount ();
TellSpeed (hwnd, start_tick, end_tick, "Alpha and colorkey Blit", 100);
/* 删除内存 DC 对象 */
DeleteMemDC (mem_dc);
此处摘自https://blog.csdn.net/jia0511/article/details/8462466
下节补充下模态和非模态