Chinaunix首页 | 论坛 | 博客
  • 博客访问: 239012
  • 博文数量: 32
  • 博客积分: 2033
  • 博客等级: 大尉
  • 技术积分: 354
  • 用 户 组: 普通用户
  • 注册时间: 2007-06-10 01:53
文章分类
文章存档

2011年(2)

2010年(16)

2009年(13)

2008年(1)

我的朋友

分类: LINUX

2009-06-22 13:39:40


kaa是kdrive的硬件加速的框架。
还是直接看代码吧。
hw/kdrive/src/kaa.c里面都是kaa的xserver这边的实现了,
然后就是driver那边的实现了。
我们硬件加速实际上就是实现driver那边,也就是说具体的工作实际上都是在driver里面做的。
注册回调函数到xserver那边,xserver那边会负责调用,然后就会调用到我们driver里面来。
这个driver和xserver是在同一个进程空间的,无论是kdrive还是xorg都一样。
对于kdrive来说,这个driver是直接编译到xserver里面也就是Xfbdev里面
对于xorg来说这个是一个单独的模块,xorg这边的框架是从kaa学习过来的,叫exa。
xorg这边加速的模块exa的实现都在xf86-video-ati等等类似这样的里面
具体下载的路径在

下面有很多video的驱动,基本上都是exa的实现。
这些东西编译完成之后都是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的驱动。
/usr/lib/xorg/modules/drivers/i810_drv.so
其他的xvmc等等这个是扩展的实现了,如果不关注的话,可以不看这些东西。

好的,说远了,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的函数了,实际上图形系统里面都是使用gc的,这样可以避免传递的参数太多,
如果感兴趣的可以看看microwindows的介绍。虽然很简陋但是基本的图形系统的设计还是可以看出来的。

对xserver上层来说调用的都是gc的操作函数,不同的gc是不一样的,所以这里有机会给我们注册这些基本的函数了。

我们还是找一个驱动来看看,我写的部分也是照抄的,因为模式都定的。
我们还是看ati的实现吧,开源的来说,ati和intel的做的不错。
ati_stub.c这个是给上层的一些最基本的接口。我们可以不用管。
一般来说,kaa的实现,都是在XXX_draw.c里面来实现的,比如ati_draw.c
我们先看看最核心的一个函数。这个drawinit是注册回调函数的。
如果大家觉得ati的做的太复杂,可以看看epson的实现,这个实现的加速比较少,所以看起来比较简单。
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 << 8) - 1;

    if (!kaaDrawInit(pScreen, &atis->kaa))
        return FALSE;

    return TRUE;
}

可以看出,实际上kaa的加速分为三类操作,这个也是kaa的核心,无非是Solid,Copy,Composite
这三类操作如下解释

Solid,
就是填充一个区域,比如我们创建一个window的时候背景一般都是白色或者灰色,实际上这个是需要填充的,注意这里的solid并不是
我们想像的简单的solid,这里有mask,有fg,还有alu,怎么说呢,实际上图形学是比较复杂的,也就是说,我们往一个区域里面画的时候,实际上这个
东西应该说是一个状态机,比如画之前是什么状态,我画什么上去,画完之后是什么效果,这个东西我一句两句实在是说不清楚。
mask就是把某些位给mask掉,fg是前景色,alu,这个是画的方法,就是说,是or,xor等等,定义的比较多,如果大家像了解,需要先补一补图形学的只是,
这个不是这里要说明的要点,不过总之,一般pc的硬件可以很简单的处理这样的状况。

Copy.
我们简单的理解,就是比如我们有一个窗口,我们现在拿鼠标来拖动这个窗口,实际上在xserver上面是这么处理的,就是把这个区域copy到新的区域,当然这个copy
的速度很快,所以我们感觉不到闪,但是如果系统很慢,或者屏幕很大,或者没有任何硬件加速,我们拖动的时候就会看到大家所说的屏幕撕开的情况,其实就是copy的速度
太慢了,实际上copy来说就是一行一行的copy,这里的处理有些是linar buffer有些是tiled buffer,不过有些pc的硬件可以很好的处理这不同的状况。
屏幕大了之后,copy的速度没变的话,由于数据量的变大,导致我们绘图看起来比较慢,所以看到上部先显示,然后下部后显示,就是我们看到的屏幕撕裂了,当然这个说的是
没有硬件加速的情况,我们这里说的是online buffer的情况,没有swap buffer的情况,kaa里面没有double buffer的处理。当然copy和solid一样,
都要考虑采用什么画法。alu.


Composite
Composite是这三种操作里面最复杂的一种了,本身composite操作就种类多。可以参考如下链接

本身composite的操作就比较多,再加上状态处理,组合就更多了,另外composite里面还要加上trasform的处理,这样导致这个地方的处理很复杂,2d的engine一般
没法完全处理这些,只能靠3d的engine来处理。

当然对应的每个类别里面都有prepare, do, done三类处理,以solid为例
PrepareSolid
Solid
DoneSolid

composite复杂一些,会多一些操作,比如CheckComposite的操作,如果发现不支持的话,就会采用软件的实现。
如果没有硬件的实现,就是使用xserver自己的软件实现,以前都是在xserver里面实现,好像现在倾向于拿到pixman这个库里面去处理了。
所以这个库现在更新的很快,有很多cpu相关的优化,arm的优化也比较多0.15.10里面加入的noen优化指令比较多,其实这个优化最早是从maemo的项目,ti的omap的cpu里面来的。
因为ti的xv的硬件有问题,暂时只能靠软件来实现。不过ti的3d的驱动做的还不错,powerVR那边支持的很好.高通的相对落后不少。



剩下的还有一些函数
比如
UploadToScreen
UploadToScratch
自己感觉好像用的频率不高。
BlockHandler
WakeupHandler
这两个函数是如果硬件需要lock的时候就会用,不过好像有些硬件不需要。留空就行了。

然后我们要实现的就是上面的Solid,Copy,Composite函数了,
比如cairo的Xlib的后端就会调用XrenderComposite,然后就会调用Composite这个函数了,如果这个函数做的快,自然 cairo就快了。
当然cairo还可以使用glitz的后端,只要有opengl就可以了.不过embedded一般都没有opengl了,不过exa/kaa这个还是可以实现的。毕竟只是2d的东西
当然也可以使用3d的engine来实现。

至于具体的实现,这里不多说了,根据硬件的功能,完整这个目的就行了,这里只是说说架构。
不同的硬件是不一样的,另外就是对上层的接口也不一样。


举一个例子来说明调用流程
kaaCopyWindow这个是gc里面的函数,注册到xserver里面去了。
当copywindow发生的时候kaa的实现就会调用kaaCopyWindow

调用下面的函数。
   fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
          0,
          &rgnDst, dx, dy, kaaCopyNtoN, 0, 0);
会调用这个函数。
kaaCopyNtoN
这个函数里面就会调用copy的硬件回调函数了,具体如下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等等里面的实现,现在看起来都慢慢移动到pixman里面去了,都是基本的像素操作,
以后xorg只管基本的逻辑了。具体的绘图或者加速,都在外边了。


因为driver一般都做成一个,所以xvideo等实现也一般就做在这个driver里面,核心的文件是ati_draw.c
因为所有的回调函数的具体实现都是在这个里面实现的,注册回调函数也是在这个函数里面实现的。

另外一个重要的文件就是ati.c这个和框架有点关系,但是也基本是一个数组,然后填充数据就行了。
kdrive和xorg不同,kdrive是直接操作fb空间的,所以这些驱动都是基于framebuffer的
kaa的内存管理也是一样。
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 */
};

这里是所有将要被调用的函数,没有注册的就是空NULL,
ATIScreenInit
里面的主要函数就是这个函数调用,
#ifdef KDRIVEFBDEV
    if (atic->use_fbdev) {
        success = fbdevScreenInitialize(screen,
                        &atis->backend_priv.fbdev);
    }
#endif

这个函数里面的主要实现
static Bool
ATIInitScreen(ScreenPtr pScreen)
{
    KdScreenPriv(pScreen);
    ATICardInfo(pScreenPriv);

#ifdef XV
    ATIInitVideo(pScreen);
#endif
    return atic->backend_funcs.initScreen(pScreen);
}

一个就是xvideo的初始化,大家看到其实就只有一行代码。

其实这里都有默认的函数,默认的就是fbdev里面的函数。

ati还是有硬件加速的reg的这些的处理,实际上对于之前我们实现的driver来说,这些东西都完全省略了,因为fb这边我基本不用任何处理。
只要使用MDP对fb来做上面的Solid,Copy,Composite的处理
对应init的函数我们也有fina的函数,比如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;
}


这里其实很多函数都是不需要实现的,可以参考epson的实现,epson实现的功能比较简单。
ati的显卡相对来说复杂一些,但是对于嵌入式来讲没有那么复杂的显示芯片(2d,3d集成)。

然后大家可能问这些个回调函数都是在什么地方调用的。
这个就是kdrive了。
hw/kdrive/src/kdrive.c里面会调用。这个是kdrive的主程序。
比如kdrive的初始化screen的函数
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;
}
比如下面,都会调用这些回调函数。
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 < KD_MAX_FB && screen->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 < screen->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又是谁调用呢,
KdInitOutput,这个函数在我们每个显卡驱动里面都会被调用,在ati_stub.c里面
void
InitOutput(ScreenInfo *pScreenInfo, int argc, char **argv)
{
    KdInitOutput(pScreenInfo, argc, argv);
}


所以这里一会在driver里面一会在xserver(kdrive)里面,大家都觉得比较混乱,
实际上就是这样的,因为kdrive自己会提供一些函数来给driver调用,而driver本来就是xserver一个进程空间的东西,所以就两边跳转,
这个其实和linux kernel里面的file system实现是很像的,cache的产生,就是在linux filesystem的框架和filesystem的driver之间跳转的时候
把内容放到cache里面去的。最新的内核不知道是怎么实现的。这个东西更新一直都很快。


每个driver都会提供InitOutput这个函数。这个是标准的driver的stub
而这个InitOutput是在Xserver初始化的时候会被调用的,会初始化input和output。
那么xserver的主入口在什么地方?
在dix/main.c里面
这个是xserver的主入口。
当然,xorg和kdrive都是一样的。
xserver实际上是一个死循环,while(1)的
这个死循环里面会处理各种消息,就是大家看到里面有dispatch的函数。
Xserver这个大框架和事件处理比较大,这里就不多说了。其实大多都是消息处理。输入,输出,window管理等等这些的。

输入输出和我们关系比较近,可以简单的说说,大家可能也比较关心,这个键盘鼠标等等是怎么工作的,比如从驱动里面到最上层的widget是怎么得到这个事件的。
打字还是很累的,尤其是用全拼输入法打这么多字。
 
阅读(2695) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-02-10 16:21:49

分析得真透彻,真正的牛人,谢谢,希望能多发些文章造福后来人