- 論壇徽章:
- 0
|
kaa是kdrive的硬件加速的框架。
還是直接看代碼吧。
hw/kdrive/src/kaa.c里面都是kaa的xserver這邊的實現(xiàn)了,
然后就是driver那邊的實現(xiàn)了。
我們硬件加速實際上就是實現(xiàn)driver那邊,也就是說具體的工作實際上都是在driver里面做的。
注冊回調(diào)函數(shù)到xserver那邊,xserver那邊會負責調(diào)用,然后就會調(diào)用到我們driver里面來。
這個driver和xserver是在同一個進程空間的,無論是kdrive還是xorg都一樣。
對于kdrive來說,這個driver是直接編譯到xserver里面也就是Xfbdev里面
對于xorg來說這個是一個單獨的模塊,xorg這邊的框架是從kaa學習過來的,叫exa。
xorg這邊加速的模塊exa的實現(xiàn)都在xf86-video-ati等等類似這樣的里面
具體下載的路徑在
http://xorg.freedesktop.org/releases/individual/driver/
下面有很多video的驅(qū)動,基本上都是exa的實現(xiàn)。
這些東西編譯完成之后都是so文件,
以intel的為例。
ailantian@vax:/mnt/sdb1/ubd/soft/xorg/temp/xorg-server-1.5.3$ dpkg -L xserver-xorg-video-intel
/.
/usr
/usr/share
/usr/share/doc
/usr/share/doc/xserver-xorg-video-intel
/usr/share/doc/xserver-xorg-video-intel/copyright
/usr/share/doc/xserver-xorg-video-intel/changelog.gz
/usr/share/doc/xserver-xorg-video-intel/README.gz
/usr/share/doc/xserver-xorg-video-intel/changelog.Debian.gz
/usr/share/xserver-xorg
/usr/share/xserver-xorg/pci
/usr/share/xserver-xorg/pci/intel.ids
/usr/share/man
/usr/share/man/man4
/usr/share/man/man4/intel.4.gz
/usr/share/bug
/usr/share/bug/xserver-xorg-video-intel
/usr/lib
/usr/lib/xorg
/usr/lib/xorg/modules
/usr/lib/xorg/modules/drivers
/usr/lib/xorg/modules/drivers/ch7017.so
/usr/lib/xorg/modules/drivers/ch7xxx.so
/usr/lib/xorg/modules/drivers/intel_drv.so
/usr/lib/xorg/modules/drivers/ivch.so
/usr/lib/xorg/modules/drivers/sil164.so
/usr/lib/xorg/modules/drivers/tfp410.so
/usr/lib/libI810XvMC.so.1.0.0
/usr/lib/libIntelXvMC.so.1.0.0
/usr/share/man/man4/i810.4.gz
/usr/share/bug/xserver-xorg-video-intel/script
/usr/lib/xorg/modules/drivers/i810_drv.so
/usr/lib/libI810XvMC.so
/usr/lib/libI810XvMC.so.1
/usr/lib/libIntelXvMC.so
/usr/lib/libIntelXvMC.so.1
ailantian@vax:/mnt/sdb1/ubd/soft/xorg/temp/xorg-server-1.5.3$
比如i810的驅(qū)動。
/usr/lib/xorg/modules/drivers/i810_drv.so
其他的xvmc等等這個是擴展的實現(xiàn)了,如果不關(guān)注的話,可以不看這些東西。
好的,說遠了,xorg的另外分出來說吧,這里還是看看kdrive的,xorg和kdrive差不多。
static const GCOps kaaOps = {
kaaFillSpans,
KdCheckSetSpans,
KdCheckPutImage,
kaaCopyArea,
KdCheckCopyPlane,
KdCheckPolyPoint,
KdCheckPolylines,
KdCheckPolySegment,
miPolyRectangle,
KdCheckPolyArc,
miFillPolygon,
kaaPolyFillRect,
miPolyFillArc,
miPolyText8,
miPolyText16,
miImageText8,
miImageText16,
kaaImageGlyphBlt,
KdCheckPolyGlyphBlt,
KdCheckPushPixels,
};
GCFuncs kaaGCFuncs = {
kaaValidateGC,
miChangeGC,
miCopyGC,
miDestroyGC,
miChangeClip,
miDestroyClip,
miCopyClip
};
上面這些都是最基本的gc的函數(shù)了,實際上圖形系統(tǒng)里面都是使用gc的,這樣可以避免傳遞的參數(shù)太多,
如果感興趣的可以看看microwindows的介紹。雖然很簡陋但是基本的圖形系統(tǒng)的設(shè)計還是可以看出來的。
對xserver上層來說調(diào)用的都是gc的操作函數(shù),不同的gc是不一樣的,所以這里有機會給我們注冊這些基本的函數(shù)了。
我們還是找一個驅(qū)動來看看,我寫的部分也是照抄的,因為模式都定的。
我們還是看ati的實現(xiàn)吧,開源的來說,ati和intel的做的不錯。
ati_stub.c這個是給上層的一些最基本的接口。我們可以不用管。
一般來說,kaa的實現(xiàn),都是在XXX_draw.c里面來實現(xiàn)的,比如ati_draw.c
我們先看看最核心的一個函數(shù)。這個drawinit是注冊回調(diào)函數(shù)的。
如果大家覺得ati的做的太復雜,可以看看epson的實現(xiàn),這個實現(xiàn)的加速比較少,所以看起來比較簡單。
Bool
ATIDrawInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
ErrorF("Screen: %d/%d depth/bpp\n", pScreenPriv->screen->fb[0].depth,
pScreenPriv->screen->fb[0].bitsPerPixel);
RegisterBlockAndWakeupHandlers(ATIBlockHandler, ATIWakeupHandler,
pScreen);
#ifdef USE_DRI
atis->using_dri = ATIDRIScreenInit(pScreen);
#endif /* USE_DRI */
memset(&atis->kaa, 0, sizeof(KaaScreenInfoRec));
atis->kaa.waitMarker = ATIWaitMarker;
atis->kaa.PrepareSolid = ATIPrepareSolid;
atis->kaa.Solid = ATISolid;
atis->kaa.DoneSolid = ATIDoneSolid;
atis->kaa.PrepareCopy = ATIPrepareCopy;
atis->kaa.Copy = ATICopy;
atis->kaa.DoneCopy = ATIDoneCopy;
/* Other acceleration will be hooked in in DrawEnable depending on
* what type of DMA gets initialized.
*/
atis->kaa.flags = KAA_OFFSCREEN_PIXMAPS;
if (atic->is_radeon) {
atis->kaa.offsetAlign = 1024;
atis->kaa.pitchAlign = 64;
} else {
/* Rage 128 compositing wants power-of-two pitches. */
atis->kaa.flags |= KAA_OFFSCREEN_ALIGN_POT;
atis->kaa.offsetAlign = 32;
/* Pitch alignment is in sets of 8 pixels, and we need to cover
* 32bpp, so 32 bytes.
*/
atis->kaa.pitchAlign = 32;
}
kaaInitTrapOffsets(8, sample_offsets_x, sample_offsets_y, 0.0, 0.0);
sample_count = (1 kaa))
return FALSE;
return TRUE;
}
可以看出,實際上kaa的加速分為三類操作,這個也是kaa的核心,無非是Solid,Copy,Composite
這三類操作如下解釋
Solid,
就是填充一個區(qū)域,比如我們創(chuàng)建一個window的時候背景一般都是白色或者灰色,實際上這個是需要填充的,注意這里的solid并不是
我們想像的簡單的solid,這里有mask,有fg,還有alu,怎么說呢,實際上圖形學是比較復雜的,也就是說,我們往一個區(qū)域里面畫的時候,實際上這個
東西應該說是一個狀態(tài)機,比如畫之前是什么狀態(tài),我畫什么上去,畫完之后是什么效果,這個東西我一句兩句實在是說不清楚。
mask就是把某些位給mask掉,fg是前景色,alu,這個是畫的方法,就是說,是or,xor等等,定義的比較多,如果大家像了解,需要先補一補圖形學的只是,
這個不是這里要說明的要點,不過總之,一般pc的硬件可以很簡單的處理這樣的狀況。
Copy.
我們簡單的理解,就是比如我們有一個窗口,我們現(xiàn)在拿鼠標來拖動這個窗口,實際上在xserver上面是這么處理的,就是把這個區(qū)域copy到新的區(qū)域,當然這個copy
的速度很快,所以我們感覺不到閃,但是如果系統(tǒng)很慢,或者屏幕很大,或者沒有任何硬件加速,我們拖動的時候就會看到大家所說的屏幕撕開的情況,其實就是copy的速度
太慢了,實際上copy來說就是一行一行的copy,這里的處理有些是linar buffer有些是tiled buffer,不過有些pc的硬件可以很好的處理這不同的狀況。
屏幕大了之后,copy的速度沒變的話,由于數(shù)據(jù)量的變大,導致我們繪圖看起來比較慢,所以看到上部先顯示,然后下部后顯示,就是我們看到的屏幕撕裂了,當然這個說的是
沒有硬件加速的情況,我們這里說的是online buffer的情況,沒有swap buffer的情況,kaa里面沒有double buffer的處理。當然copy和solid一樣,
都要考慮采用什么畫法。alu.
Composite
Composite是這三種操作里面最復雜的一種了,本身composite操作就種類多?梢詤⒖既缦骆溄
http://en.wikipedia.org/wiki/Alpha_compositing
本身composite的操作就比較多,再加上狀態(tài)處理,組合就更多了,另外composite里面還要加上trasform的處理,這樣導致這個地方的處理很復雜,2d的engine一般
沒法完全處理這些,只能靠3d的engine來處理。
當然對應的每個類別里面都有prepare, do, done三類處理,以solid為例
PrepareSolid
Solid
DoneSolid
composite復雜一些,會多一些操作,比如CheckComposite的操作,如果發(fā)現(xiàn)不支持的話,就會采用軟件的實現(xiàn)。
如果沒有硬件的實現(xiàn),就是使用xserver自己的軟件實現(xiàn),以前都是在xserver里面實現(xiàn),好像現(xiàn)在傾向于拿到pixman這個庫里面去處理了。
所以這個庫現(xiàn)在更新的很快,有很多cpu相關(guān)的優(yōu)化,arm的優(yōu)化也比較多0.15.10里面加入的noen優(yōu)化指令比較多,其實這個優(yōu)化最早是從maemo的項目,ti的omap的cpu里面來的。
因為ti的xv的硬件有問題,暫時只能靠軟件來實現(xiàn)。不過ti的3d的驅(qū)動做的還不錯,powerVR那邊支持的很好.高通的相對落后不少。
剩下的還有一些函數(shù)
比如
UploadToScreen
UploadToScratch
自己感覺好像用的頻率不高。
BlockHandler
WakeupHandler
這兩個函數(shù)是如果硬件需要lock的時候就會用,不過好像有些硬件不需要。留空就行了。
然后我們要實現(xiàn)的就是上面的Solid,Copy,Composite函數(shù)了,
比如cairo的Xlib的后端就會調(diào)用XrenderComposite,然后就會調(diào)用Composite這個函數(shù)了,如果這個函數(shù)做的快,自然 cairo就快了。
當然cairo還可以使用glitz的后端,只要有opengl就可以了.不過embedded一般都沒有opengl了,不過exa/kaa這個還是可以實現(xiàn)的。畢竟只是2d的東西
當然也可以使用3d的engine來實現(xiàn)。
至于具體的實現(xiàn),這里不多說了,根據(jù)硬件的功能,完整這個目的就行了,這里只是說說架構(gòu)。
不同的硬件是不一樣的,另外就是對上層的接口也不一樣。
舉一個例子來說明調(diào)用流程
kaaCopyWindow這個是gc里面的函數(shù),注冊到xserver里面去了。
當copywindow發(fā)生的時候kaa的實現(xiàn)就會調(diào)用kaaCopyWindow
調(diào)用下面的函數(shù)。
fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
0,
&rgnDst, dx, dy, kaaCopyNtoN, 0, 0);
會調(diào)用這個函數(shù)。
kaaCopyNtoN
這個函數(shù)里面就會調(diào)用copy的硬件回調(diào)函數(shù)了,具體如下kaa.c
這是一個標準的硬件處理流程,其他的流程也類似。
if (pScreenPriv->enabled &&
(pSrcPixmap = kaaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y)) &&
(pDstPixmap = kaaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y)) &&
(*pKaaScr->info->PrepareCopy) (pSrcPixmap,
pDstPixmap,
dx,
dy,
pGC ? pGC->alu : GXcopy,
pGC ? pGC->planemask : FB_ALLONES))
{
while (nbox--)
{
(*pKaaScr->info->Copy) (pbox->x1 + dx + src_off_x,
pbox->y1 + dy + src_off_y,
pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
pbox->x2 - pbox->x1,
pbox->y2 - pbox->y1);
pbox++;
}
(*pKaaScr->info->DoneCopy) ();
kaaMarkSync (pDstDrawable->pScreen);
大家也能看到,一次preparecopy之后會有多次的copy,最后是donecopy。
如果沒有硬件加速的話,走的就是這邊
else
{
kaaWaitSync (pDstDrawable->pScreen);
fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC,
pbox, nbox, dx, dy, reverse, upsidedown,
bitplane, closure);
}
然后就跑到pixman里面去了,fbimage,fbcopy等等里面的實現(xiàn),現(xiàn)在看起來都慢慢移動到pixman里面去了,都是基本的像素操作,
以后xorg只管基本的邏輯了。具體的繪圖或者加速,都在外邊了。
因為driver一般都做成一個,所以xvideo等實現(xiàn)也一般就做在這個driver里面,核心的文件是ati_draw.c
因為所有的回調(diào)函數(shù)的具體實現(xiàn)都是在這個里面實現(xiàn)的,注冊回調(diào)函數(shù)也是在這個函數(shù)里面實現(xiàn)的。
另外一個重要的文件就是ati.c這個和框架有點關(guān)系,但是也基本是一個數(shù)組,然后填充數(shù)據(jù)就行了。
kdrive和xorg不同,kdrive是直接操作fb空間的,所以這些驅(qū)動都是基于framebuffer的
kaa的內(nèi)存管理也是一樣。
KdCardFuncs ATIFuncs = {
ATICardInit, /* cardinit */
ATIScreenInit, /* scrinit */
ATIInitScreen, /* initScreen */
ATIFinishInitScreen, /* finishInitScreen */
ATICreateResources, /* createRes */
ATIPreserve, /* preserve */
ATIEnable, /* enable */
ATIDPMS, /* dpms */
ATIDisable, /* disable */
ATIRestore, /* restore */
ATIScreenFini, /* scrfini */
ATICardFini, /* cardfini */
ATICursorInit, /* initCursor */
ATICursorEnable, /* enableCursor */
ATICursorDisable, /* disableCursor */
ATICursorFini, /* finiCursor */
ATIRecolorCursor, /* recolorCursor */
ATIDrawInit, /* initAccel */
ATIDrawEnable, /* enableAccel */
ATIDrawDisable, /* disableAccel */
ATIDrawFini, /* finiAccel */
ATIGetColors, /* getColors */
ATIPutColors, /* putColors */
};
這里是所有將要被調(diào)用的函數(shù),沒有注冊的就是空NULL,
ATIScreenInit
里面的主要函數(shù)就是這個函數(shù)調(diào)用,
#ifdef KDRIVEFBDEV
if (atic->use_fbdev) {
success = fbdevScreenInitialize(screen,
&atis->backend_priv.fbdev);
}
#endif
這個函數(shù)里面的主要實現(xiàn)
static Bool
ATIInitScreen(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATICardInfo(pScreenPriv);
#ifdef XV
ATIInitVideo(pScreen);
#endif
return atic->backend_funcs.initScreen(pScreen);
}
一個就是xvideo的初始化,大家看到其實就只有一行代碼。
其實這里都有默認的函數(shù),默認的就是fbdev里面的函數(shù)。
ati還是有硬件加速的reg的這些的處理,實際上對于之前我們實現(xiàn)的driver來說,這些東西都完全省略了,因為fb這邊我基本不用任何處理。
只要使用MDP對fb來做上面的Solid,Copy,Composite的處理
對應init的函數(shù)我們也有fina的函數(shù),比如deregister Xvideo
static void
ATIScreenFini(KdScreenInfo *screen)
{
ATIScreenInfo *atis = (ATIScreenInfo *)screen->driver;
ATICardInfo *atic = screen->card->driver;
#ifdef XV
ATIFiniVideo(screen->pScreen);
#endif
atic->backend_funcs.scrfini(screen);
xfree(atis);
screen->driver = 0;
}
這里其實很多函數(shù)都是不需要實現(xiàn)的,可以參考epson的實現(xiàn),epson實現(xiàn)的功能比較簡單。
ati的顯卡相對來說復雜一些,但是對于嵌入式來講沒有那么復雜的顯示芯片(2d,3d集成)。
然后大家可能問這些個回調(diào)函數(shù)都是在什么地方調(diào)用的。
這個就是kdrive了。
hw/kdrive/src/kdrive.c里面會調(diào)用。這個是kdrive的主程序。
比如kdrive的初始化screen的函數(shù)
void
KdInitScreen (ScreenInfo *pScreenInfo,
KdScreenInfo *screen,
int argc,
char **argv)
{
KdCardInfo *card = screen->card;
(*card->cfuncs->scrinit) (screen);
if (!card->cfuncs->initAccel)
screen->dumb = TRUE;
if (!card->cfuncs->initCursor)
screen->softCursor = TRUE;
}
比如下面,都會調(diào)用這些回調(diào)函數(shù)。
Bool
KdScreenInit(int index, ScreenPtr pScreen, int argc, char **argv)
{
KdScreenInfo *screen = kdCurrentScreen;
KdCardInfo *card = screen->card;
KdPrivScreenPtr pScreenPriv;
int fb;
/*
* note that screen->fb is set up for the nominal orientation
* of the screen; that means if randr is rotated, the values
* there should reflect a rotated frame buffer (or shadow).
*/
Bool rotated = (screen->randr & (RR_Rotate_90|RR_Rotate_270)) != 0;
int width, height, *width_mmp, *height_mmp;
KdAllocatePrivates (pScreen);
pScreenPriv = KdGetScreenPriv(pScreen);
if (!rotated)
{
width = screen->width;
height = screen->height;
width_mmp = &screen->width_mm;
height_mmp = &screen->height_mm;
}
else
{
width = screen->height;
height = screen->width;
width_mmp = &screen->height_mm;
height_mmp = &screen->width_mm;
}
screen->pScreen = pScreen;
pScreenPriv->screen = screen;
pScreenPriv->card = card;
for (fb = 0; fb fb[fb].depth; fb++)
pScreenPriv->bytesPerPixel[fb] = screen->fb[fb].bitsPerPixel >> 3;
pScreenPriv->dpmsState = KD_DPMS_NORMAL;
#ifdef PANORAMIX
dixScreenOrigins[pScreen->myNum] = screen->origin;
#endif
if (!monitorResolution)
monitorResolution = 75;
/*
* This is done in this order so that backing store wraps
* our GC functions; fbFinishScreenInit initializes MI
* backing store
*/
if (!fbSetupScreen (pScreen,
screen->fb[0].frameBuffer,
width, height,
monitorResolution, monitorResolution,
screen->fb[0].pixelStride,
screen->fb[0].bitsPerPixel))
{
return FALSE;
}
/*
* Set colormap functions
*/
pScreen->InstallColormap = KdInstallColormap;
pScreen->UninstallColormap = KdUninstallColormap;
pScreen->ListInstalledColormaps = KdListInstalledColormaps;
pScreen->StoreColors = KdStoreColors;
pScreen->SaveScreen = KdSaveScreen;
pScreen->CreateWindow = KdCreateWindow;
#if KD_MAX_FB > 1
if (screen->fb[1].depth)
{
if (!fbOverlayFinishScreenInit (pScreen,
screen->fb[0].frameBuffer,
screen->fb[1].frameBuffer,
width, height,
monitorResolution, monitorResolution,
screen->fb[0].pixelStride,
screen->fb[1].pixelStride,
screen->fb[0].bitsPerPixel,
screen->fb[1].bitsPerPixel,
screen->fb[0].depth,
screen->fb[1].depth))
{
return FALSE;
}
}
else
#endif
{
if (!fbFinishScreenInit (pScreen,
screen->fb[0].frameBuffer,
width, height,
monitorResolution, monitorResolution,
screen->fb[0].pixelStride,
screen->fb[0].bitsPerPixel))
{
return FALSE;
}
}
/*
* Fix screen sizes; for some reason mi takes dpi instead of mm.
* Rounding errors are annoying
*/
if (*width_mmp)
pScreen->mmWidth = *width_mmp;
else
*width_mmp = pScreen->mmWidth;
if (*height_mmp)
pScreen->mmHeight = *height_mmp;
else
*height_mmp = pScreen->mmHeight;
/*
* Plug in our own block/wakeup handlers.
* miScreenInit installs NoopDDA in both places
*/
pScreen->BlockHandler = KdBlockHandler;
pScreen->WakeupHandler = KdWakeupHandler;
#ifdef RENDER
if (!fbPictureInit (pScreen, 0, 0))
return FALSE;
#endif
if (card->cfuncs->initScreen)
if (!(*card->cfuncs->initScreen) (pScreen))
return FALSE;
if (!screen->dumb && card->cfuncs->initAccel)
if (!(*card->cfuncs->initAccel) (pScreen))
screen->dumb = TRUE;
if (screen->off_screen_base memory_size)
KdOffscreenInit (pScreen);
#ifdef PSEUDO8
(void) p8Init (pScreen, PSEUDO8_USE_DEFAULT);
#endif
if (card->cfuncs->finishInitScreen)
if (!(*card->cfuncs->finishInitScreen) (pScreen))
return FALSE;
#if 0
fbInitValidateTree (pScreen);
#endif
#if 0
pScreen->backingStoreSupport = Always;
miInitializeBackingStore (pScreen);
#endif
/*
* Wrap CloseScreen, the order now is:
* KdCloseScreen
* miBSCloseScreen
* fbCloseScreen
*/
pScreenPriv->CloseScreen = pScreen->CloseScreen;
pScreen->CloseScreen = KdCloseScreen;
pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources;
pScreen->CreateScreenResources = KdCreateScreenResources;
if (screen->softCursor ||
!card->cfuncs->initCursor ||
!(*card->cfuncs->initCursor) (pScreen))
{
/* Use MI for cursor display and event queueing. */
screen->softCursor = TRUE;
miDCInitialize(pScreen, &kdPointerScreenFuncs);
}
if (!fbCreateDefColormap (pScreen))
{
return FALSE;
}
KdSetSubpixelOrder (pScreen, screen->randr);
/*
* Enable the hardware
*/
if (!kdEnabled)
{
kdEnabled = TRUE;
if(kdOsFuncs->Enable)
(*kdOsFuncs->Enable) ();
}
if (screen->mynum == card->selected)
{
if(card->cfuncs->preserve)
(*card->cfuncs->preserve) (card);
if(card->cfuncs->enable)
if (!(*card->cfuncs->enable) (pScreen))
return FALSE;
pScreenPriv->enabled = TRUE;
if (!screen->softCursor && card->cfuncs->enableCursor)
(*card->cfuncs->enableCursor) (pScreen);
KdEnableColormap (pScreen);
if (!screen->dumb && card->cfuncs->enableAccel)
(*card->cfuncs->enableAccel) (pScreen);
}
return TRUE;
}
那么KdInitScreen又是誰調(diào)用呢,
KdInitOutput,這個函數(shù)在我們每個顯卡驅(qū)動里面都會被調(diào)用,在ati_stub.c里面
void
InitOutput(ScreenInfo *pScreenInfo, int argc, char **argv)
{
KdInitOutput(pScreenInfo, argc, argv);
}
所以這里一會在driver里面一會在xserver(kdrive)里面,大家都覺得比較混亂,
實際上就是這樣的,因為kdrive自己會提供一些函數(shù)來給driver調(diào)用,而driver本來就是xserver一個進程空間的東西,所以就兩邊跳轉(zhuǎn),
這個其實和linux kernel里面的file system實現(xiàn)是很像的,cache的產(chǎn)生,就是在linux filesystem的框架和filesystem的driver之間跳轉(zhuǎn)的時候
把內(nèi)容放到cache里面去的。最新的內(nèi)核不知道是怎么實現(xiàn)的。這個東西更新一直都很快。
每個driver都會提供InitOutput這個函數(shù)。這個是標準的driver的stub
而這個InitOutput是在Xserver初始化的時候會被調(diào)用的,會初始化input和output。
那么xserver的主入口在什么地方?
在dix/main.c里面
這個是xserver的主入口。
當然,xorg和kdrive都是一樣的。
xserver實際上是一個死循環(huán),while(1)的
這個死循環(huán)里面會處理各種消息,就是大家看到里面有dispatch的函數(shù)。
Xserver這個大框架和事件處理比較大,這里就不多說了。其實大多都是消息處理。輸入,輸出,window管理等等這些的。
輸入輸出和我們關(guān)系比較近,可以簡單的說說,大家可能也比較關(guān)心,這個鍵盤鼠標等等是怎么工作的,比如從驅(qū)動里面到最上層的widget是怎么得到這個事件的。
打字還是很累的,尤其是用全拼輸入法打這么多字。
本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u1/40978/showart_1972995.html |
|