composite extension由两部分实现,一部分为X11 server,另一部分为compositor。两者之间通过扩展请求实现。
Compositor调用libXcomposite库实现composite扩展协议通信,X11 Server源码中集成了composite扩展功能,实现在源码树的composite目录下。
画布
图形系统的内容都渲染在画布上,如:X11的Pixmap,Wayland的wl_surface。图形系统启动时为每个屏幕创建一个画布,默认情况下,每个窗口都共享该画布,如下图所示。在X11 server中,在创建屏幕时调用CreateScreenResources回调函数创建画布,由miCreateScreenResources调用CreatePixmap创建画布。在创建窗口(Window)过程中,调CreateWindow回调函数,最终由fbCreateWindow函数将屏幕画布分配给窗口。
为了实现窗口合成功能,图形系统可为窗口创建新的画布,下图为compositor之后窗口与Pixmap的关系,为每个顶级窗口创建一个画布。以X11 Server为例,调用CreatePixmap回调函数,最终由fbCreatePixmap创建Pixmap;再调用SetWindowPixmap回调函数,最终由_fbSetWindowPixmap将窗口与pixmap关联。
Pixmap画布内存在fbCreatePixmap分配了一段连续的主机内存,当使用GPU渲染时,会调用以下操作分配GPU内存
// 申明分配GPU buffer glGenBuffers // 指定Buffer类型 glBindBuffer(GL_PIXEL_PACK_BUFFER) // 指定尺寸创建GPU内存 glBufferData(GL_PIXEL_PACK_BUFFER) // 指定GPU内存访问权限 glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE) // 将GPU内存与framebuffer关联 glBindFramebuffer(GL_FRAMEBUFFER)
X11 Server端的实现
请求扩展
compositor向X11 server发送请求,X11 server影响请求,并做响应处理。
compositor request | X11 server process function | description |
---|---|---|
XCompositeQueryVersion | ProcCompositeQueryVersion | 获取Composite扩展版本,当前版本为0.4 |
XCompositeRedirectWindow | ProcCompositeRedirectWindow | 创建指定窗口的CompWindow,一般为CompositeRedirectManual类型 |
XCompositeRedirectSubwindows | ProcCompositeRedirectSubwindows | 为指定窗口的直接子窗口创建CompWindow,一般为CompositeRedirectManual类型 |
XCompositeUnredirectWindow | ProcCompositeUnredirectWindow | 销毁指定窗口的CompWindow |
XCompositeUnredirectSubwindows | ProcCompositeUnredirectSubwindows | 销毁指定窗口的子窗口的CompWindow |
XCompositeCreateRegionFromBorderClip | ProcCompositeCreateRegionFromBorderClip | 从包含窗口边框的区域创建CompWindow区间 |
XCompositeNameWindowPixmap | ProcCompositeNameWindowPixmap | 获取指定窗口的pixmap |
XCompositeGetOverlayWindow | ProcCompositeGetOverlayWindow | 创建CompOverlayClient,若不存在overlay window,则创建一个,属性为(CWBackPixmap | CWOverrideRedirect) |
XCompositeReleaseOverlayWindow | ProcCompositeReleaseOverlayWindow | 销毁CompOverlayClient |
从mutter的实现看,MetaCompositorServer只调用了XCompositeRedirectSubwindows一个扩展接口,为根窗口的直接子窗口创建compWindow。而MetaCompositorX11调用了较多接口。
回调函数
X11 Server调用CompositeExtensionInit注册扩展协议的请求和回调函数。Composite扩展不支持8位仿真色彩。compScreenInit注册回调函数。
当窗口的visual,depth等属性与父窗口一致时,创建窗口时,该窗口共享与父窗口的pixmap,即窗口画图内容显示在父窗口的pixmap中。
自动生成CompWindow的条件:
visual与父窗口不同:创建一个类型为RedirectDrawAutomatic的CompWindow,窗口在MapWindow操作中分配新的pixmap
修改窗口属性,backingStore设置为WhenMapped或Always,创建CompWindow;设置为NotUseful,销毁CompWindow。client可以在CreateWindow时指定窗口属性,或者同ChangeWindowAttributes请求修改窗口属性
另外一种场景时,compositor client调用XCompositeRedirectWindow或XCompositeRedirectSubwindows创建CompWindow。
callback | realize | description |
---|---|---|
CreateWindow | compCreateWindow | 当窗口的visual与父窗口不同时,创建窗口的CompWindow |
DestroyWindow | compDestroyWindow | 销毁CompWindow |
RealizeWindow | compRealizeWindow | 为具有CompWindow的窗口创建一个独立的pixmap |
UnrealizeWindow | compUnrealizeWindow | 释放pixmap副本 |
PositionWindow | compPositionWindow | 重新计算pixmap的位置 |
CopyWindow | compCopyWindow | 从CompWindow中的pixmap从拷贝数据至窗口中的pixmap |
MoveWindow | compMoveWindow | 销毁CompWindow中的pOldPixmap(旧的pixmap),与 |
ResizeWindow | compResizeWindow | 销毁CompWindow中的pixmap,先旧的pixmap销毁,再在ConfigNotify缓冲窗口的pixmap |
ReparentWindow | compReparentWindow | 销毁与原父窗口的CompWindow,以及CompSubwindows,创建与新父窗口的CompWindow,以及CompSubwindows |
ConfigNotify | compConfigNotify | 窗口大小有变化时,将窗口的pixmap交给CompWindow缓冲,然后重新分配pixmap |
ClipNotify | compClipNotify | 转换CompWindow Clip区域坐标 |
ChangeWindowAttributes | compChangeWindowAttributes | 修改CWBackingStore掩码窗口属性时,创建或销毁CompWindow |
ChangeBorderWidth | compChangeBorderWidth | 销毁CompWindow缓冲的pixmap |
InstallColormap | compInstallColormap | 检查色彩映射表是否存在,若存在,则不再安装 |
SourceValidate | compSourceValidate | 合成子窗口内容,将子窗口的pixmap合入窗口的pixmap |
CloseScreen | compCloseScreen | 关闭屏幕 |
Picture Screen Callback
屏幕图形操作回调包括几何形状,图元等操作,有不同的实现,与机器无关的实现,帧缓冲,glamor和damage相关实现,其中,glamor的实现替换帧缓冲和机器无关实现,帧缓冲替换机器无关实现。damage封装了glamor的实现。
callback | machine independence | framebuffer | glamor | damage |
---|---|---|---|---|
RealizeGlyph | miRealizeGlyph | |||
UnrealizeGlyph | miUnrealizeGlyph | fbUnrealizeGlyph | ||
Composite | fbComposite | glamor_composite | damageComposite | |
Glyphs | miGlyphs | fbGlyphs | glamor_composite_glyphs | damageGlyphs |
CompositeRects | miCompositeRects | glamor_composite_rectangles | ||
Trapezoids | fbTrapezoids | glamor_trapezoids | ||
Triangles | fbTriangles | glamor_triangles | ||
RasterizeTrapezoid | fbRasterizeTrapezoid | |||
AddTraps | fbAddTraps | glamor_add_traps | damageAddTraps | |
AddTriangles | fbAddTriangles | |||
TriStrip | miTriStrip | |||
TriFan | miTriFan | |||
CreatePicture | miCreatePicture | |||
DestroyPicture | miDestroyPicture | |||
ChangePictureClip | miChangePictureClip | |||
DestroyPictureClip | miDestroyPictureClip | |||
ChangePicture | miChangePicture | |||
ValidatePicture | miValidatePicture | |||
InitIndexed | miInitIndexed | |||
CloseIndexed | miCloseIndexed | |||
UpdateIndexed | miUpdateIndexed | |||
ChangePictureTransform | miChangePictureTransform | |||
ChangePictureFilter | miChangePictureFilter |
mutter compositor实现
compositor根据窗口层级创建和销毁CompWindow,其创建的CompWindow类型为CompositeRedirectManual,共有3种创建CompWindow的操作。
compositor在初始化后,创建一个composite window,属性为CWOverrideRedirect,对X11的根窗口发送XCompositeRedirectSubwindows,对根窗口的所有直接子窗口创建CompWindow。
在mutter中,一个MetaSurfaceActorX11对应的window会调用XCompositeRedirectWindow创建一个CompWindow。由调用ClutterActor::constructed回调函数meta_window_actor_constructed实现,meta_window_actor_constructed ->init_surface_actor ->meta_surface_actor_x11_new,这个过程只有使用MetaCompositorX11时才会调用,而非根模式下使用MetaCompositorServer和MetaWaylandCompositor,不会调用该过程,
MetaSurfaceActorX11更新pixmap时,调用XCompositeNameWindowPixmap获取指定Window的pixmap,最终创建CoglTexturePixmapX11与pixmap关联,在非根模式下,使用的时MetaWindowActorWayland。
Wayland compositor使用XCompositeRedirectSubwindows对根窗口的子窗口创建CompWindow,具体作用说明如下:
为根窗口创建一个CompClientWindow(ccw)和CompSubwindows(csw),update均设置为CompositeRedirectManual,csw管理ccw链表。ccw的client为wayland compositor
调用compRedirectWindow为每个顶级窗口创建一个CompWindow(cw)以及CompClientWindow(ccw),其update均为CompositeRedirectManual,cw管理ccw链表,将窗口的redirectDraw设置为RedirectDrawManual。
CreateWindow时,调用compCreateWindow对每个顶层窗口(根窗口的子窗口)创建一个CompWindow(cw)以及CompClientWindow(ccw)
ReparentWindow时,调用compReparentWindow,销毁原顶层窗口的CompWindow(cw)以及CompClientWindow(ccw)
从上面的实现看,Wayland compositor对窗口管理器的页框和override direct窗口创建了CompWindow,其它窗口未管理。在X11 server处理窗口堆叠处理时,从miValidateTree实现看到,redirectDraw为RedirectDrawManual的窗口作为透明窗口处理,不覆盖显示区域。该函数计算父窗口的子窗口的可剪接区域以及各窗口的exposed和borderExposed区域。
// mutter检测xwayland已经启动后,对x11 display进行初始化,做为X11 server的client,初始化相关扩展 // 扩展包括:xsync, xshape, xcomposite, xdamage, xfixes, xi gboolean meta_display_init_x11_finish (MetaDisplay *display, GAsyncResult *result, GError **error){ MetaX11Display *x11_display = meta_x11_display_new (display, error); if (!x11_display) return FALSE; display->x11_display = x11_display; g_signal_emit (display, display_signals[X11_DISPLAY_SETUP], 0); meta_x11_display_create_guard_window (x11_display); if (!display->display_opening){ g_signal_emit (display, display_signals[X11_DISPLAY_OPENED], 0); // 创建composite window,属性为CWOverrideRedirect,保存在x11_display->wm_cm_selection_window meta_x11_display_set_cm_selection (x11_display); // 对已有的顶层窗口,增加页框窗口。(窗口管理器功能) meta_display_manage_all_xwindows (display); // 对根窗口发送XCompositeRedirectSubwindows,为其子窗口创建CompWindow meta_compositor_redirect_x11_windows (display->compositor); } return TRUE; }
ProcCompositeRedirectSubwindows
ProcCompositeRedirectSubwindows调用compRedirectSubwindows实现其功能
// update一般为CompositeRedirectManual int compRedirectSubwindows(ClientPtr pClient, WindowPtr pWin, int update){ CompSubwindowsPtr csw = GetCompSubwindows(pWin); CompClientWindowPtr ccw; WindowPtr pChild; // Only one Manual update is allowed if (csw && update == CompositeRedirectManual) for (ccw = csw->clients; ccw; ccw = ccw->next) if (ccw->update == CompositeRedirectManual) return BadAccess; // Allocate per-client per-window structure // The client *could* allocate multiple, but while supported, it is not expected to be common ccw = malloc(sizeof(CompClientWindowRec)); if (!ccw) return BadAlloc; ccw->id = FakeClientID(pClient->index); ccw->update = update; // Now make sure there's a per-window structure to hang this from if (!csw) { csw = malloc(sizeof(CompSubwindowsRec)); if (!csw) { free(ccw); return BadAlloc; } csw->update = CompositeRedirectAutomatic; csw->clients = 0; dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, csw); } // Redirect all existing windows,相反方向遍历,compRedirectWindow涉及窗口栈的变化 for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) { // 创建window的compWindow,以及独立的pixmap int ret = compRedirectWindow(pClient, pChild, update); if (ret != Success) { // skip } } // Hook into subwindows list ccw->next = csw->clients; csw->clients = ccw; if (!AddResource(ccw->id, CompositeClientSubwindowsType, pWin)) return BadAlloc; if (ccw->update == CompositeRedirectManual) { csw->update = CompositeRedirectManual; // tell damage extension that damage events for this client are critical output DamageExtSetCritical(pClient, TRUE); pWin->inhibitBGPaint = TRUE; } return Success; } // 为pWin创建compWindow,update为CompositeRedirectManual int compRedirectWindow(ClientPtr pClient, WindowPtr pWin, int update){ CompWindowPtr cw = GetCompWindow(pWin); CompClientWindowPtr ccw; CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen); WindowPtr pLayerWin; Bool anyMarked = FALSE; if (pWin == cs->pOverlayWin) { return Success; } if (!pWin->parent) return BadMatch; // Only one Manual update is allowed if (cw && update == CompositeRedirectManual) for (ccw = cw->clients; ccw; ccw = ccw->next) if (ccw->update == CompositeRedirectManual) return BadAccess; // Allocate per-client per-window structure // The client *could* allocate multiple, but while supported, it is not expected to be common ccw = malloc(sizeof(CompClientWindowRec)); if (!ccw) return BadAlloc; ccw->id = FakeClientID(pClient->index); ccw->update = update; // Now make sure there's a per-window structure to hang this from if (!cw) { cw = malloc(sizeof(CompWindowRec)); if (!cw) { free(ccw); return BadAlloc; } // 创建damage cw->damage = DamageCreate(compReportDamage, compDestroyDamage, DamageReportNonEmpty, FALSE, pWin->drawable.pScreen, pWin); if (!cw->damage) { free(ccw); free(cw); return BadAlloc; } // 标记与pWin重叠的窗口,有重叠则返回true // miMarkOverlappedWindows深度遍历pWin和相邻窗口以及所有子窗口是否有重叠 // miMarkWindow记录与pWin有重叠的窗口尺寸 anyMarked = compMarkWindows(pWin, &pLayerWin); RegionNull(&cw->borderClip); cw->update = CompositeRedirectAutomatic; cw->clients = 0; cw->oldx = COMP_ORIGIN_INVALID; cw->oldy = COMP_ORIGIN_INVALID; cw->damageRegistered = FALSE; cw->damaged = FALSE; cw->pOldPixmap = NullPixmap; dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, cw); } ccw->next = cw->clients; cw->clients = ccw; if (!AddResource(ccw->id, CompositeClientWindowType, pWin)) return BadAlloc; if (ccw->update == CompositeRedirectManual) { if (!anyMarked) anyMarked = compMarkWindows(pWin, &pLayerWin); if (cw->damageRegistered) { DamageUnregister(cw->damage); cw->damageRegistered = FALSE; } cw->update = CompositeRedirectManual; } else if (cw->update == CompositeRedirectAutomatic && !cw->damageRegistered) { if (!anyMarked) anyMarked = compMarkWindows(pWin, &pLayerWin); } // 创建或者销毁pixmap,此创建为window创建一个pixmap if (!compCheckRedirect(pWin)) { FreeResource(ccw->id, RT_NONE); return BadAlloc; } if (anyMarked) // 有重叠,则处理重叠窗口部分 compHandleMarkedWindows(pWin, pLayerWin); return Success; } static void compHandleMarkedWindows(WindowPtr pWin, WindowPtr pLayerWin) { ScreenPtr pScreen = pWin->drawable.pScreen; // miValidateTree,根据窗口树,计算需要重绘的窗口及其区域 (*pScreen->ValidateTree) (pLayerWin->parent, pLayerWin, VTOther); // miHandleValidateExposures,深度优先,先绘制边框,再绘制背景,然后发送Expose事件给客户端绘制内容 (*pScreen->HandleExposures) (pLayerWin->parent); // xf86XVPostValidateTree,视频扩展协议使用,该场景不处理 if (pScreen->PostValidateTree) (*pScreen->PostValidateTree) (pLayerWin->parent, pLayerWin, VTOther); }
damage
damage记录画布变化的区域,以及相关操作。每个画布有一个damage列表,保存在PixmapPtr的damagePixPrivateKey私有属性中,不同的damage可以响应不同操作。每个window有额外的damage列表,保存在WindowPtr的damageWinPrivateKey私有属性中,主要原因是一个窗口树可能共享一个画布,即子窗口没有独立的画布,使用父窗口的画布,而子窗口有独立的damage操作。window与pixmap的关系可以通过SetWindowPixmap回调函数进行修改
typedef struct _damage { DamagePtr pNext; // pixmap的damage列表 DamagePtr pNextWin; // window的damage列表 RegionRec damage; // 变化区域,初始化为空 DamageReportLevel damageLevel; // 触发report的级别,DamageCreate时赋值 Bool isInternal; // DamageCreate时赋值 void *closure; // DamageCreate时赋值 Bool isWindow; // 是否为窗口的damage,既可以是Window,也可以是pixmap,DamageRegister时赋值 DrawablePtr pDrawable; // 画布指针(window or pixmap),DamageRegister时赋值 DamageReportFunc damageReport; DamageDestroyFunc damageDestroy; Bool reportAfter; RegionRec pendingDamage; // will be flushed post submission at the latest ScreenPtr pScreen; } DamageRec; // 触发report的级别 typedef enum _damageReportLevel { DamageReportRawRegion, // 传递新增的变化区域给damageReport,每次都触发report DamageReportDeltaRegion, // 有变化,传递变化区域 DamageReportBoundingBox, // 边界有变化,传递整个damage区域 DamageReportNonEmpty, // 由空到非空变化,传递整个damage区域 DamageReportNone } DamageReportLevel; // Damage的回调函数 const DamageScreenFuncsRec miFuncs = { miDamageCreate, miDamageRegister, miDamageUnregister, miDamageDestroy }; void miDamageCreate(DamagePtr pDamage) {} void miDamageRegister(DrawablePtr pDrawable, DamagePtr pDamage){ if (pDrawable->type == DRAWABLE_WINDOW) // 深度优先遍历窗口,更新窗口的序列号:pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; TraverseTree((WindowPtr)pDrawable, damageRegisterVisit, NULL); else pDrawable->serialNumber = NEXT_SERIAL_NUMBER; } void miDamageUnregister(DrawablePtr pDrawable, DamagePtr pDamage) { if (pDrawable->type == DRAWABLE_WINDOW) TraverseTree((WindowPtr)pDrawable, damageRegisterVisit, NULL); else pDrawable->serialNumber = NEXT_SERIAL_NUMBER; } void miDamageDestroy(DamagePtr pDamage) {}
CompositeRedirectAutomatic与damage
在CreateWindow时,compCreateWindow在compRedirectWindow函数中调用DamageCreate为CompWindow创建Damage,保存在CompWindowPtr->damage中,并在compCheckRedirect函数中调用compAllocPixmap分配一个新的画布,并将damage注册至该window的画布中。然而,在CompositeRedirectManual类型下,未调用DamageRegister将damage注册注册至画布中。由X11 server实现compositor功能时,下面过程才有效。
// DamageReportNonEmpty,可显示区域变化时,当区域不为空时,调用compReportDamage // cw->damage = DamageCreate(compReportDamage,compDestroyDamage,DamageReportNonEmpty,FALSE, pWin->drawable.pScreen, pWin); static void compReportDamage(DamagePtr pDamage, RegionPtr pRegion, void *closure){ WindowPtr pWin = (WindowPtr) closure; ScreenPtr pScreen = pWin->drawable.pScreen; CompScreenPtr cs = GetCompScreen(pScreen); CompWindowPtr cw = GetCompWindow(pWin); if (!cs->pendingScreenUpdate) { // 插入工作队列,在主线程下次迭代时处理 QueueWorkProc(compScreenUpdate, serverClient, pScreen); cs->pendingScreenUpdate = TRUE; } cw->damaged = TRUE; // 标记祖父窗口,子孙窗口已被修改,即pWin->damagedDescendants = TRUE; compMarkAncestors(pWin); } static Bool compScreenUpdate(ClientPtr pClient, void *closure){ ScreenPtr pScreen = closure; CompScreenPtr cs = GetCompScreen(pScreen); // 递归调用深度优先递归调用,若窗口有变化,调用compWindowUpdateAutomatic更新窗口 compPaintChildrenToWindow(pScreen->root); cs->pendingScreenUpdate = FALSE; // Next damage will restore the worker return TRUE; } void compPaintChildrenToWindow(WindowPtr pWin){ WindowPtr pChild; if (!pWin->damagedDescendants) return; // 将所有子窗口内容合成至父窗口中 for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) compPaintWindowToParent(pChild); pWin->damagedDescendants = FALSE; } static void compPaintWindowToParent(WindowPtr pWin){ // 递归处理窗口的所有子窗口 compPaintChildrenToWindow(pWin); if (pWin->redirectDraw != RedirectDrawNone) { CompWindowPtr cw = GetCompWindow(pWin); if (cw->damaged) { // 将窗口内容合成至父窗口中 compWindowUpdateAutomatic(pWin); cw->damaged = FALSE; } } } static void compWindowUpdateAutomatic(WindowPtr pWin) { CompWindowPtr cw = GetCompWindow(pWin); ScreenPtr pScreen = pWin->drawable.pScreen; WindowPtr pParent = pWin->parent; PixmapPtr pSrcPixmap = (*pScreen->GetWindowPixmap) (pWin); PictFormatPtr pSrcFormat = PictureWindowFormat(pWin); PictFormatPtr pDstFormat = PictureWindowFormat(pWin->parent); int error; RegionPtr pRegion = DamageRegion(cw->damage); PicturePtr pSrcPicture = CreatePicture(0, &pSrcPixmap->drawable, pSrcFormat, 0, 0, serverClient, &error); XID subwindowMode = IncludeInferiors; PicturePtr pDstPicture = CreatePicture(0, &pParent->drawable, pDstFormat, CPSubwindowMode, &subwindowMode, serverClient, &error); // First move the region from window to screen coordinates RegionTranslate(pRegion, pWin->drawable.x, pWin->drawable.y); // Clip against the "real" border clip RegionIntersect(pRegion, pRegion, &cw->borderClip); // Now translate from screen to dest coordinates RegionTranslate(pRegion, -pParent->drawable.x, -pParent->drawable.y); // Clip the picture SetPictureClipRegion(pDstPicture, 0, 0, pRegion); // And paint CompositePicture(PictOpSrc, pSrcPicture, 0, pDstPicture, 0, 0, 0, 0, pSrcPixmap->screen_x - pParent->drawable.x, pSrcPixmap->screen_y - pParent->drawable.y, pSrcPixmap->drawable.width, pSrcPixmap->drawable.height); FreePicture(pSrcPicture, 0); FreePicture(pDstPicture, 0); // Empty the damage region. This has the nice effect of rendering the translations above harmless DamageEmpty(cw->damage); } void CompositePicture(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) { PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen); ValidatePicture(pSrc); if (pMask) ValidatePicture(pMask); ValidatePicture(pDst); op = ReduceCompositeOp(op, pSrc, pMask, pDst, xSrc, ySrc, width, height); if (op == PictOpDst) return; // 调用damageComposite -> glamor_composite 合成图像 (*ps->Composite) (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height); }
CompositeRedirectManual与damage
xwayland采用无根模式,由Wayland compositor实现compositor功能,xwayland在realize window时对顶层窗口创建并注册damage,实现在xwl_realize_window函数中,其调用register_damage创建和注册damage,将damage保存在Window的xwl_damage_private_key私有属性中。
static Bool register_damage(WindowPtr window) { // 为window创建damage,当damage区域由空至非空时,触发report操作 DamagePtr damage = DamageCreate(damage_report, damage_destroy, DamageReportNonEmpty, FALSE, window->drawable.pScreen, window); if (damage == NULL) { ErrorF("Failed creating damage\n"); return FALSE; } // 为window注册damage DamageRegister(&window->drawable, damage); DamageSetReportAfterOp(damage, TRUE); dixSetPrivate(&window->devPrivates, &xwl_damage_private_key, damage); return TRUE; } // window显示内容有变化,则加入xwl_screen->damage_window_list列表中,在blockHandler回调中处理 static void damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data){ WindowPtr window = data; struct xwl_window *xwl_window = xwl_window_get(window); struct xwl_screen *xwl_screen; if (!xwl_window) return; xwl_screen = xwl_window->xwl_screen; if (xwl_window->present_flipped) { // This damage is from a Present flip, which already committed a new buffer for the surface, // so we don't need to do anything in response RegionEmpty(DamageRegion(pDamage)); xorg_list_del(&xwl_window->link_damage); xwl_window->present_flipped = FALSE; return; } if (xorg_list_is_empty(&xwl_window->link_damage)) xorg_list_add(&xwl_window->link_damage, &xwl_screen->damage_window_list); } // 在主线程中由BlockHandler调用,处理上次迭代时等待处理的事务 static void block_handler(void *data, void *timeout) { struct xwl_screen *xwl_screen = data; xwl_screen_post_damage(xwl_screen); xwl_dispatch_events (xwl_screen); } // 向Wayland compositor发送damage请求,由Wayland compositor处理damage内容 static void xwl_screen_post_damage(struct xwl_screen *xwl_screen){ struct xwl_window *xwl_window, *next_xwl_window; struct xorg_list commit_window_list; xorg_list_init(&commit_window_list); // 遍历damage_window_list列表中所有的window,这些window的显示内容均有变化 xorg_list_for_each_entry_safe(xwl_window, next_xwl_window, &xwl_screen->damage_window_list, link_damage) { // If we're waiting on a frame callback from the server, don't attach a new buffer. if (xwl_window->frame_callback) continue; if (!xwl_window->allow_commits) continue; if (xwl_screen->glamor && !xwl_glamor_allow_commits(xwl_window)) continue; // 向Wayland compositor发送damage请求,更新damage区域,并将自身的damage区域清空 xwl_window_post_damage(xwl_window); // 从damage_window_list列表中删除window xorg_list_del(&xwl_window->link_damage); // 并将window加入commit_window_list临时列表中 xorg_list_append(&xwl_window->link_damage, &commit_window_list); } if (xorg_list_is_empty(&commit_window_list)) return; if (xwl_glamor_needs_buffer_flush(xwl_screen)) glamor_block_handler(xwl_screen->screen); // 遍历commit_window_list提交列表,向Wayland compositor提交请求,处理damage内容 xorg_list_for_each_entry_safe(xwl_window, next_xwl_window, &commit_window_list, link_damage) { wl_surface_commit(xwl_window->surface); // 从commit_window_list列表中删除window xorg_list_del(&xwl_window->link_damage); } }
Graphic Context ops
图形上下文操作子主要对图形和图元的渲染操作,glamor在glamor_init函数中替换了framebuffer的GCOps回调函数,damage在DamageSetup函数中包装了glamor的回调函数。
name | framebuffer | glamor | damage |
---|---|---|---|
FillSpans | fbFillSpans | glamor_fill_spans | damageFillSpans |
SetSpans | fbSetSpans | glamor_set_spans | damageSetSpans |
PutImage | fbPutImage | glamor_put_image | damagePutImage |
CopyArea | fbCopyArea | glamor_copy_area | damageCopyArea |
CopyPlane | fbCopyPlane | glamor_copy_plane | damageCopyPlane |
PolyPoint | fbPolyPoint | glamor_poly_point | damagePolyPoint |
Polylines | fbPolyLine | glamor_poly_lines | damagePolylines |
PolySegment | fbPolySegment | glamor_poly_segment | damagePolySegment |
PolyRectangle | fbPolyRectangle | miPolyRectangle | damagePolyRectangle |
PolyArc | fbPolyArc | miPolyArc | damagePolyArc |
FillPolygon | miFillPolygon | miFillPolygon | damageFillPolygon |
PolyFillRect | fbPolyFillRect | glamor_poly_fill_rect | damagePolyFillRect |
PolyFillArc | fbPolyFillArc | miPolyFillArc | damagePolyFillArc |
PolyText8 | miPolyText8 | glamor_poly_text8 | damagePolyText8 |
PolyText16 | miPolyText16 | glamor_poly_text16 | damagePolyText16 |
ImageText8 | miImageText8 | glamor_image_text8 | damageImageText8 |
ImageText16 | miImageText16 | glamor_image_text16 | damageImageText16 |
ImageGlyphBlt | fbImageGlyphBlt | miImageGlyphBlt | damageImageGlyphBlt |
PolyGlyphBlt | fbPolyGlyphBlt | glamor_poly_glyph_blt | damagePolyGlyphBlt |
PushPixels | fbPushPixels | glamor_push_pixels | damagePushPixels |
Graphic Context Functions
图形上下文函数主要对图形上下文进行操作,glamor替换了framebuffer的GCFuncs,damage包装了glamor的GCFuncs回调函数。
name | framebuffer | glamor | damage |
---|---|---|---|
ValidateGC | fbValidateGC | glamor_validate_gc | damageValidateGC |
ChangeGC | miChangeGC | miChangeGC | damageChangeGC |
CopyGC | miCopyGC | miCopyGC | damageCopyGC |
DestroyGC | miDestroyGC | glamor_destroy_gc | damageDestroyGC |
ChangeClip | miChangeClip | miChangeClip | damageChangeClip |
DestroyClip | miDestroyClip | miDestroyClip | damageDestroyClip |
CopyClip | miCopyClip | miCopyClip | damageCopyClip |
Damage extension
在DamageExtensionInit函数中注册Damage的扩展请求和事件。由client创建和销毁Damage,Damage发生变化时,发送DamageNotify事件通知。
/* Requests */ #define X_DamageQueryVersion 0 #define X_DamageCreate 1 #define X_DamageDestroy 2 #define X_DamageSubtract 3 #define X_DamageAdd 4 /* Events */ #define XDamageNotify 0 #define XDamageNumberEvents (XDamageNotify + 1) /* Constants */ #define XDamageReportRawRectangles 0 // 有新的区域 #define XDamageReportDeltaRectangles 1 // 区域有变化 #define XDamageReportBoundingBox 2 // 边界有变化 #define XDamageReportNonEmpty 3 // 空至非空转换 static int (*ProcDamageVector[XDamageNumberRequests]) (ClientPtr) = { ProcDamageQueryVersion, ProcDamageCreate, ProcDamageDestroy, ProcDamageSubtract, ProcDamageAdd, }; |
0 评论