7.radeon驱动初始化代码解析.
由上面对xserver初始化的介绍,可以看到,在初始化过程中主要是显卡驱动的三个函数的调用
Probe , PreInit , ScreenInit
以下以radeon驱动为例(xorg-xserver-video-ati-6.13.1),介绍驱动对显卡的初始化过程,以及图形加速中使用的函数。
(1)Probe函数
在radeon驱动中,probe函数主要是
static Bool
radeon_pci_probe(
DriverPtr pDriver,
int entity_num,
struct pci_device *device,
intptr_t match_data
)
{
return radeon_get_scrninfo(entity_num, (void *)device);
}
在radeon_get_scrninfo函数中有:主要是对pScrn和pENT的初始化。
在pScrn的初始化中给出了将要调用的PreInit 和ScreenInit函数
#ifdef XF86DRM_MODE
if (kms == 1) {
pScrn->PreInit = RADEONPreInit_KMS;
pScrn->ScreenInit = RADEONScreenInit_KMS;
pScrn->SwitchMode = RADEONSwitchMode_KMS;
pScrn->AdjustFrame = RADEONAdjustFrame_KMS;
pScrn->EnterVT = RADEONEnterVT_KMS;
pScrn->LeaveVT = RADEONLeaveVT_KMS;
pScrn->FreeScreen = RADEONFreeScreen_KMS;
pScrn->ValidMode = RADEONValidMode;
} else
#endif
{
pScrn->PreInit = RADEONPreInit;
pScrn->ScreenInit = RADEONScreenInit;
pScrn->SwitchMode = RADEONSwitchMode;
pScrn->AdjustFrame = RADEONAdjustFrame;
pScrn->EnterVT = RADEONEnterVT;
pScrn->LeaveVT = RADEONLeaveVT;
pScrn->FreeScreen = RADEONFreeScreen;
pScrn->ValidMode = RADEONValidMode;
}
不妨已RADEONPreInit_KMS , RADEONScreenInit_KMS为例介绍驱动PreInit和ScreenInit过程
(2)PreInit
RADEONPreInit_KMS在结构上大体可以分为三个部分(虽然不严格),
a)pScrn->driverPrivate的初始化
例如:
info = RADEONPTR(pScrn);
info->pEnt = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
f (!radeon_alloc_dri(pScrn))
return FALSE;
其实对pScrn->driverPrivate的初始化贯穿了整个PreInit,但是在前面比较集中。
b)drm的初始化
radeon_open_drm_master(pScrn)
调用drmOpen打开内核drm设备
drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8)
drmCommandWriteRead(info->dri->drmFD, DRM_RADEON_GEM_INFO, &mminfo, sizeof(mminfo))
等做其他方面的初始化
c)一些相关模块的load
例如:
xf86LoadSubModule(pScrn, "fb")
load framebuffer相关的so
!xf86LoadSubModule(pScrn, "ramdac")
load 与光标显示相关模块
RADEONPreInitAccel_KMS(pScrn)
根据加速方式选择决定load shadowfb 还是exa模块
细节很多大体上可以分这三个部分理解
(3)ScreenInit
RADEONScreenInit_KMS要比RADEONPreInit_KMS杂乱
但也可以看作如下几个部分
a)对pScrn->driverPrivate的比较集中的初始化
例如:
info->bufmgr = radeon_bo_manager_gem_ctor(info->dri->drmFD);
info->cs = radeon_cs_create(info->csm, RADEON_BUFFER_SIZE/4);
等比较明显的
以及
radeon_setup_kernel_mem(pScreen);
初始化地址映射相关的info信息
b)fbScreenInit
初始化framebuffer信息
c) 显示图像像素相关的初始化及fbPictureInit
例如:
if (pScrn->bitsPerPixel > 8) {
VisualPtr visual;
visual = pScreen->visuals + pScreen->numVisuals;
while (--visual >= pScreen->visuals) {
if ((visual->class | DynamicClass) == DirectColor) {
visual->offsetRed = pScrn->offset.red;
visual->offsetGreen = pScrn->offset.green;
visual->offsetBlue = pScrn->offset.blue;
visual->redMask = pScrn->mask.red;
visual->greenMask = pScrn->mask.green;
visual->blueMask = pScrn->mask.blue;
}
}
}
fbPictureInit (pScreen, 0, 0);
#ifdef RENDER
if ((s = xf86GetOptValString(info->Options, OPTION_SUBPIXEL_ORDER))) {
if (strcmp(s, "RGB") == 0) subPixelOrder = SubPixelHorizontalRGB;
else if (strcmp(s, "BGR") == 0) subPixelOrder = SubPixelHorizontalBGR;
else if (strcmp(s, "NONE") == 0) subPixelOrder = SubPixelNone;
PictureSetSubpixelOrder (pScreen, subPixelOrder);
}
#endif
这部分是fbPictureInit和对像素RGB顺序的初始化
d)BackStore相关的初始化
例如:
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
"Initializing backing store\n");
miInitializeBackingStore(pScreen);
xf86SetBackingStore(pScreen);
e)加速函数相关的初始化
例如:
if (info->r600_shadow_fb) {
xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n");
info->accelOn = FALSE;
} else {
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
"Initializing Acceleration\n");
if (RADEONAccelInit(pScreen)) {
xf86DrvMsg(scrnIndex, X_INFO, "Acceleration enabled\n");
info->accelOn = TRUE;
} else {
xf86DrvMsg(scrnIndex, X_ERROR,
"Acceleration initialization failed\n");
xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n");
info->accelOn = FALSE;
}
}
中的RADEONAccelInit(pScreen)函数
下面会对RADEONAccelInit(pScreen)函数做仔细的分析
f)光标显示相关的初始化
例如:
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
"Initializing DPMS\n");
xf86DPMSInit(pScreen, xf86DPMSSet, 0);
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
"Initializing Cursor\n");
xf86SetSilkenMouse(pScreen);
miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) {
if (RADEONCursorInit_KMS(pScreen)) {
}
}
其中xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)的判断决定对光标显示是否使用硬件加速
g)其他的初始化
例如CloseScreen,BlockHandler 等变量赋值
Crtc初始化xf86CrtcScreenInit (pScreen)
和colormap相关的drmmode_setup_colormap(pScreen, pScrn)。
(4)RADEONAccelInit
需要重点介绍的是RADEONAccelInit函数,因为在这个函数中引入了初始化图像加速相关的函数
以笔者调试过的RS780为例:
其调用的图形加速相关的初始化是R600DrawInit(pScreen)函数,因为驱动不支持RS780的xaa加速,而软件加速shodowfb效果不好,必须使用exa加速。
R600DrawInit()函数中包含了众多加速函数的初始化其中最重要的是如下5系列函数
a)Solid相关的函数
info->accel_state->exa->PrepareSolid = R600PrepareSolid;
info->accel_state->exa->Solid = R600Solid;
info->accel_state->exa->DoneSolid = R600DoneSolid;
Solid即是向某一区域填充色的操作
b)Copy相关的函数
info->accel_state->exa->PrepareCopy = R600PrepareCopy;
info->accel_state->exa->Copy = R600Copy;
info->accel_state->exa->DoneCopy = R600DoneCopy;
Copy是不同区域直接拷贝的函数
c)Composite函数
info->accel_state->exa->CheckComposite = R600CheckComposite;
info->accel_state->exa->PrepareComposite = R600PrepareComposite;
info->accel_state->exa->Composite = R600Composite;
info->accel_state->exa->DoneComposite = R600DoneComposite;
Composite是不同窗口组合在一起的操作
d)UploadToScreen函数
info->accel_state->exa->UploadToScreen = R600UploadToScreenCS;
UploadToScreen是向framebuffer拷贝矩形域数据的函数
e)DownloadFromScreen函数
info->accel_state->exa->DownloadFromScreen = R600DownloadFromScreenCS;
DownloadFromScreen是从framebuffer拷贝出矩形域数据的函数
至此radeon驱动初始化相关的内容做了一次简单的浏览。