...
Compositor调用libXcomposite库实现composite扩展协议通信,X11 Server源码中集成了composite扩展功能,实现在源码树的composite目录下。
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
画布
图形系统的内容都渲染在画布上,如: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一个扩展接口。而MetaCompositorX11调用了较多接口。从mutter的实现看,MetaCompositorServer只调用了XCompositeRedirectSubwindows一个扩展接口,为根窗口的直接子窗口创建compWindow。而MetaCompositorX11调用了较多接口。
回调函数
X11 Server调用CompositeExtensionInit注册扩展协议的请求和回调函数。Composite扩展不支持8位仿真色彩。compScreenInit注册回调函数Server调用CompositeExtensionInit注册扩展协议的请求和回调函数。Composite扩展不支持8位仿真色彩。compScreenInit注册回调函数。
当窗口的visual,depth等属性与父窗口一致时,创建窗口时,该窗口共享与父窗口的pixmap,即窗口画图内容显示在父窗口的pixmap中。
...
visual与父窗口不同:创建一个类型为RedirectDrawAutomatic的CompWindow,窗口在MapWindow操作中分配新的pixmap
修改窗口属性,backingStore设置为WhenMapped或Always,窗口CompWindow;设置为NotUseful,销毁CompWindow。client可以在CreateWindow时指定窗口属性,或者同ChangeWindowAttributes请求修改窗口属性修改窗口属性,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中的pixmap,why???销毁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 |
CompositeRectsmiCompositeRects | 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,具体合成功能在X11 server中完成。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;
} |
damage
在compRedirectWindow函数中调用DamageCreate为CompWindow创建Damage。在CompositeRedirectManual下,未主动调用DamageRegister注册damage。
代码块 | ||
---|---|---|
| ||
// 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;
}
// 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) {} |
Graphic Context ops
...
::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回调函数图形上下文函数主要对图形上下文进行操作,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事件通知。
|
|
|
|
|
|
|
|