Mesa初始化流程重学习之eglInitialize
引言
说来也惭愧,Mesa搞了这么久了,每次都想深入下,可是每次都是浅尝辄止了。这次趁着有了一定的闲暇时间并且有了调试景嘉微显卡的机会,还是想重新学习下,深入研究下!不说达到某个程度吗,至少能充实点!
这里我使用的mesa版本是22.3.7!其它版本可能存在一定差异,应该不大!
tree src/ -L 1
src/
├── amd
├── android_stub
├── asahi
├── broadcom
├── c11
├── compiler
├── drm-shim
├── egl
├── etnaviv
├── freedreno
├── gallium
├── gbm
├── getopt
├── glx
├── gtest
├── hgl
├── imagination
├── imgui
├── intel
├── loader
├── mapi
├── mesa
├── meson.build
├── microsoft
├── nouveau
├── panfrost
├── tool
├── util
├── virtio
└── vulkan
29 directories, 1 file
tree src/gallium/ -L 2
src/gallium/
├── auxiliary
│ ├── cso_cache
│ ├── draw
│ ├── driver_ddebug
│ ├── driver_noop
│ ├── driver_trace
│ ├── gallivm
│ ├── hud
│ ├── indices
│ ├── meson.build
│ ├── nir
│ ├── os
│ ├── pipebuffer
│ ├── pipe-loader
│ ├── postprocess
│ ├── renderonly
│ ├── rtasm
│ ├── target-helpers
│ ├── tessellator
│ ├── tgsi
│ ├── translate
│ ├── util
│ └── vl
├── drivers
│ ├── asahi
│ ├── crocus
│ ├── d3d12
│ ├── etnaviv
│ ├── freedreno
│ ├── i915
│ ├── iris
│ ├── lima
│ ├── llvmpipe
│ ├── xxx_gpu
│ ├── nouveau
│ ├── panfrost
│ ├── r300
│ ├── r600
│ ├── radeonsi
│ ├── softpipe
│ ├── svga
│ ├── tegra
│ ├── v3d
│ ├── vc4
│ ├── virgl
│ └── zink
├── frontends
│ ├── clover
│ ├── d3d10umd
│ ├── dri
│ ├── glx
│ ├── hgl
│ ├── lavapipe
│ ├── nine
│ ├── omx
│ ├── osmesa
│ ├── rusticl
│ ├── va
│ ├── vdpau
│ ├── wgl
│ └── xa
├── include
│ ├── frontend
│ ├── pipe
│ └── winsys
├── meson.build
├── README.portability
├── targets
│ ├── d3d10sw
│ ├── d3dadapter9
│ ├── dri
│ ├── dri-vdpau.dyn
│ ├── haiku-softpipe
│ ├── lavapipe
│ ├── libgl-gdi
│ ├── libgl-xlib
│ ├── omx
│ ├── opencl
│ ├── osmesa
│ ├── pipe-loader
│ ├── rusticl
│ ├── va
│ ├── vdpau
│ ├── wgl
│ └── xa
├── tests
│ ├── meson.build
│ ├── python
│ ├── trivial
│ └── unit
├── tools
│ ├── addr2line.sh
│ └── trace
└── winsys
├── amdgpu
├── asahi
├── crocus
├── d3d12
├── etnaviv
├── freedreno
├── i915
├── iris
├── kmsro
├── lima
├── xxx_gpu
├── nouveau
├── panfrost
├── radeon
├── svga
├── sw
├── tegra
├── v3d
├── vc4
└── virgl
108 directories, 6 files
一. 核心结构体和关系
_EGLDisplay和dri2_egl_display之间的关系
typedef struct _egl_display _EGLDisplay;
struct _egl_display
{
...
_EGLPlatformType Platform; /**< The type of the platform display */
void *PlatformDisplay; /**< A pointer to the platform display */
_EGLDevice *Device; //这里的Driver指向_eglDriver,实现在Egl_dri2.c
const _EGLDriver *Driver; /**< Matched driver of the display */
...
/* these fields are set by the driver during init */
void *DriverData; /**< Driver private data */指向dri2_egl_display
//disp->DriverData = (void *) dri2_dpy;
_EGLExtensions Extensions; /**< Extensions supported */
...
}
struct dri2_egl_display
{
const struct dri2_egl_display_vtbl *vtbl;
mtx_t lock;
int dri2_major;
int dri2_minor;
__DRIscreen *dri_screen; //这个screen很重要
bool own_dri_screen;
const __DRIconfig **driver_configs;
void *driver;
const __DRIcoreExtension *core; //这些会在初始化的时候被赋值,指向target的dri前端
const __DRIimageDriverExtension *image_driver;
const __DRIdri2Extension *dri2;
const __DRIswrastExtension *swrast;
const __DRIkopperExtension *kopper;
const __DRI2flushExtension *flush;
const __DRI2flushControlExtension *flush_control;
const __DRItexBufferExtension *tex_buffer;
const __DRIimageExtension *image;
const __DRIrobustnessExtension *robustness;
const __DRI2configQueryExtension *config;
const __DRI2fenceExtension *fence;
const __DRI2bufferDamageExtension *buffer_damage;
const __DRI2blobExtension *blob;
const __DRI2rendererQueryExtension *rendererQuery;
const __DRI2interopExtension *interop;
const __DRIconfigOptionsExtension *configOptions;
const __DRImutableRenderBufferDriverExtension *mutable_render_buffer;
int fd;
/* dri2_initialize/dri2_terminate increment/decrement this count, so does
* dri2_make_current (tracks if there are active contexts/surfaces). */
int ref_count;
bool own_device;
bool invalidate_available;
int min_swap_interval;
int max_swap_interval;
int default_swap_interval;
#ifdef HAVE_DRM_PLATFORM
struct gbm_dri_device *gbm_dri;
#endif
char *driver_name;
const __DRIextension **loader_extensions;
const __DRIextension **driver_extensions;
#ifdef HAVE_X11_PLATFORM
xcb_connection_t *conn;
xcb_screen_t *screen;
bool swap_available;
#ifdef HAVE_DRI3
bool multibuffers_available;
int dri3_major_version;
int dri3_minor_version;
int present_major_version;
int present_minor_version;
struct loader_dri3_extensions loader_dri3_ext;
struct loader_dri3_screen_resources screen_resources;
#endif
#endif
#ifdef HAVE_WAYLAND_PLATFORM
struct wl_display *wl_dpy;
struct wl_display *wl_dpy_wrapper;
struct wl_registry *wl_registry;
struct wl_drm *wl_server_drm;
struct wl_drm *wl_drm;
uint32_t wl_drm_version, wl_drm_name;
struct wl_shm *wl_shm;
struct wl_event_queue *wl_queue;
struct zwp_linux_dmabuf_v1 *wl_dmabuf;
struct dri2_wl_formats formats;
struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback;
struct dmabuf_feedback_format_table format_table;
bool authenticated;
uint32_t capabilities;
char *device_name;
#endif
#ifdef HAVE_ANDROID_PLATFORM
const gralloc_module_t *gralloc;
/* gralloc vendor usage bit for front rendering */
uint32_t front_rendering_usage;
#endif
bool is_render_node;
bool is_different_gpu;
};
可以通过_EGLDisplay的成员DriverData找到dri2_egl_display,并且dri2_dpy是一个非常重要的结构体!
_EGLDisplay *disp
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
__DRIscreen dri_screen pipe_screen之间关联
各种srceend的起点,是从dri2_egl_display开始的,它们之间的关联如下:
struct dri2_egl_display
{
...
__DRIscreen *dri_screen;
...
}
//这块image_driver和dri2的extensions怎么赋值来的,后面会具体分析
dri2_dpy->dri_screen = dri2_dpy->image_driver->createNewScreen2(...)或者
dri2_dpy->dri_screen = dri2_dpy->dri2->createNewScreen2(...)
我们接下来看看__DRIscreen的定义
typedef struct __DRIscreenRec __DRIscreen;
struct __DRIscreenRec {
/**
static const struct __DRIDriverVtableExtensionRec galliumdrm_vtable = {
.base = { __DRI_DRIVER_VTABLE, 1 },
.vtable = &galliumdrm_driver_api,
};
这里的driver指向galliumdrm_driver_api
psp->driver =
((__DRIDriverVtableExtension *)driver_extensions[i])->vtable;
**/
const struct __DriverAPIRec *driver;
int myNum;
int fd;
void *driverPrivate;
void *loaderPrivate;
const __DRIextension **extensions;
const __DRIswrastLoaderExtension *swrast_loader;
const __DRIkopperLoaderExtension *kopper_loader;
struct {
const __DRIdri2LoaderExtension *loader;
const __DRIimageLookupExtension *image;
const __DRIuseInvalidateExtension *useInvalidate;
const __DRIbackgroundCallableExtension *backgroundCallable;
} dri2;
struct {
const __DRIimageLoaderExtension *loader;
} image;
struct {
const __DRImutableRenderBufferLoaderExtension *loader;
} mutableRenderBuffer;
driOptionCache optionInfo;
driOptionCache optionCache;
unsigned int api_mask;
};
结构体dri_screen定义:
struct dri_screen
{
struct st_manager base;
__DRIscreen *sPriv;//指向__DRIscreen
boolean throttle;
struct st_config_options options;
/* Which postprocessing filters are enabled. */
unsigned pp_enabled[PP_FILTERS];
/* drm */
int fd;
boolean can_share_buffer;
struct pipe_loader_device *dev;
/* hooks filled in by dri2 & drisw */
__DRIimage * (*lookup_egl_image)(struct dri_screen *ctx, void *handle);
boolean (*validate_egl_image)(struct dri_screen *ctx, void *handle);
__DRIimage * (*lookup_egl_image_validated)(struct dri_screen *ctx, void *handle);
/* DRI exts that vary based on gallium pipe_screen caps. */
__DRIimageExtension image_extension;
__DRI2bufferDamageExtension buffer_damage_extension;
/* DRI exts on this screen. Populated at init time based on device caps. */
const __DRIextension *screen_extensions[14];
...
};
struct st_manager
{
struct pipe_screen *screen;//这里又和pipe_screen勾搭上了
...
}
dri_screen和__DRIscreen是如何建立联系的,或者说他们之间的关系是什么:
__DRIscreen * sPriv
struct dri_screen *screen;
struct pipe_screen *pscreen = NULL;
screen->sPriv = sPriv;
sPriv->driverPrivate = (void *)screen;
真可以说的上是你中有我,我中有你的典范啊。相互关联对方!
dri_screen和pipe_screen是如何建立联系的,或者说他们之间的关系是什么:
这里就不兜圈子了,直接上关系:
//src/gallium/frontends/dri/dri_screen.c
const __DRIconfig **
dri_init_screen_helper(struct dri_screen *screen,
struct pipe_screen *pscreen)
{
screen->base.screen = pscreen;
...
}
最后可以得到如下的一张关系表,其中厂家会对dri_screen进行扩展,通过结构体的继承
二.Mesa下eglInitialize初始化流程
搞通了这个流程,基本把Mesa的基本框架打通了。这里我们一步一步来分析,不具体代码详细分析,只有关键地方会详细分析:
//src/egl/drivers/dri2/egl_dri2.c
const _EGLDriver _eglDriver = {
.Initialize = dri2_initialize,
.Terminate = dri2_terminate,
.CreateContext = dri2_create_context,
.DestroyContext = dri2_destroy_context,
.MakeCurrent = dri2_make_current,
.CreateWindowSurface = dri2_create_window_surface,
.CreatePixmapSurface = dri2_create_pixmap_surface,
.CreatePbufferSurface = dri2_create_pbuffer_surface,
.DestroySurface = dri2_destroy_surface,
.GetProcAddress = dri2_get_proc_address,
.WaitClient = dri2_wait_client,
.WaitNative = dri2_wait_native,
.BindTexImage = dri2_bind_tex_image,
.ReleaseTexImage = dri2_release_tex_image,
.SwapInterval = dri2_swap_interval,
.SwapBuffers = dri2_swap_buffers,
.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage,
.SwapBuffersRegionNOK = dri2_swap_buffers_region,
.SetDamageRegion = dri2_set_damage_region,
.PostSubBufferNV = dri2_post_sub_buffer,
.CopyBuffers = dri2_copy_buffers,
.QueryBufferAge = dri2_query_buffer_age,
.CreateImageKHR = dri2_create_image,
.DestroyImageKHR = dri2_destroy_image_khr,
.CreateWaylandBufferFromImageWL = dri2_create_wayland_buffer_from_image,
.QuerySurface = dri2_query_surface,
.QueryDriverName = dri2_query_driver_name,
.QueryDriverConfig = dri2_query_driver_config,
#ifdef HAVE_LIBDRM
.CreateDRMImageMESA = dri2_create_drm_image_mesa,
.ExportDRMImageMESA = dri2_export_drm_image_mesa,
.ExportDMABUFImageQueryMESA = dri2_export_dma_buf_image_query_mesa,
.ExportDMABUFImageMESA = dri2_export_dma_buf_image_mesa,
.QueryDmaBufFormatsEXT = dri2_query_dma_buf_formats,
.QueryDmaBufModifiersEXT = dri2_query_dma_buf_modifiers,
#endif
#ifdef HAVE_WAYLAND_PLATFORM
.BindWaylandDisplayWL = dri2_bind_wayland_display_wl,
.UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl,
.QueryWaylandBufferWL = dri2_query_wayland_buffer_wl,
#endif
.GetSyncValuesCHROMIUM = dri2_get_sync_values_chromium,
.GetMscRateANGLE = dri2_get_msc_rate_angle,
.CreateSyncKHR = dri2_create_sync,
.ClientWaitSyncKHR = dri2_client_wait_sync,
.SignalSyncKHR = dri2_signal_sync,
.WaitSyncKHR = dri2_server_wait_sync,
.DestroySyncKHR = dri2_destroy_sync,
.GLInteropQueryDeviceInfo = dri2_interop_query_device_info,
.GLInteropExportObject = dri2_interop_export_object,
.GLInteropFlushObjects = dri2_interop_flush_objects,
.DupNativeFenceFDANDROID = dri2_dup_native_fence_fd,
.SetBlobCacheFuncsANDROID = dri2_set_blob_cache_funcs,
};
eglInitialize(...)//src/egl/main/eglapi.c
_eglDriver.Initialize(disp)
dri2_initialize(...)//src/egl/drivers/dri2/egl_dri2.c
dri2_initialize_android(disp)//src/egl/drivers/dri2/platform_android.c
这里我们对dri2_initialize_android拿出来,另开分析,只是让后面自己回过头看更加清楚!
dri2_initialize_android(_EGLDisplay *disp)
struct dri2_egl_display *dri2_dpy;
dri2_dpy = calloc(1, sizeof(*dri2_dpy));
disp->DriverData = (void *) dri2_dpy;
ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
(const hw_module_t **)&dri2_dpy->gralloc);
device_opened = droid_open_device(disp, disp->Options.ForceSoftware);
dri2_dpy->vtbl = &droid_display_vtbl;
droid_open_device(...)// src/egl/drivers/dri2/platform_android.c
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp)
dri2_dpy->fd = loader_open_device(device->nodes[node_type])
droid_probe_device(...)
droid_load_driver(..)//这个非常重要,加载驱动
dri2_dpy->loader_extensions = droid_image_loader_extensions;
dri2_load_driver_dri3(...)
dri2_create_screen(...)//构建screen,关于scrren的关系图前面已经放出来了,详见章节3
我们接下来分析dri2_load_driver_dri3的调用流程,代码流程比较多,只能一步步的来:
static const struct dri2_extension_match dri3_driver_extensions[] = {
{ __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
{ __DRI_IMAGE_DRIVER, 1, offsetof(struct dri2_egl_display, image_driver) },
{ NULL, 0, 0 }
};
dri2_load_driver_dri3(...)//src/egl/drivers/dri2/egl_dri2.c
dri2_load_driver_common(disp, dri3_driver_extensions)
extensions = dri2_open_driver(disp)//详见章节2.1
dri2_bind_extensions(dri2_dpy, driver_extensions, extensions, false)//详见章节2.2
dri2_dpy->driver_extensions = extensions
2.1 dri2_open_driver
我们接下来重点分析该函数:
dri2_open_driver()//src/egl/drivers/dri2/egl_dri2.c
const struct __DRIextensionRec **(*get_extensions)(void);
void *driver = loader_open_driver_lib(driver_name, "_dri", search_path_vars,
DEFAULT_DRIVER_DIR, true);//加载dri库
get_extensions_name = loader_get_extensions_name(driver_name)//拼接驱动extensions名称,这里的拼接后是__driDriverGetExtensions_xxx_gpu
get_extensions = dlsym(driver, get_extensions_name)//加载函数符号表等
这里的__driDriverGetExtensions_xxx_gpu函数符号表是怎么拼凑成的了,如果我们通过grep在mesa搜索,怎么搜索也搜不到了。它是通过宏定义实现的。它的定义如下:
//src/gallium/targets/dri/target.c
#define DEFINE_LOADER_DRM_ENTRYPOINT(drivername) \
const __DRIextension **__driDriverGetExtensions_##drivername(void); \
PUBLIC const __DRIextension **__driDriverGetExtensions_##drivername(void) \
{ \
return galliumdrm_driver_extensions; \
}
#if defined(GALLIUM_MWV207)
DEFINE_LOADER_DRM_ENTRYPOINT(xxx_gpu); //这里我们也可以扩展,自己的驱动,譬如XXX参照这个
#endif
这里我们重点关注galliumdrm_driver_extensions的实现,我们接着继续往下看:
注意它的实现在代码是在frontends前端目录代码下
//src/gallium/frontends/dri/dri2.c
const __DRIextension *galliumdrm_driver_extensions[] = {
&driCoreExtension.base,
&driImageDriverExtension.base,
&driDRI2Extension.base,
&gallium_config_options.base,
&galliumdrm_vtable.base,
NULL
};
//src/gallium/frontends/dri/dri_util.c
/** Core interface */
const __DRIcoreExtension driCoreExtension = {
.base = { __DRI_CORE, 2 },
.createNewScreen = NULL,
.destroyScreen = driDestroyScreen,
.getExtensions = driGetExtensions,
.getConfigAttrib = driGetConfigAttrib,
.indexConfigAttrib = driIndexConfigAttrib,
.createNewDrawable = NULL,
.destroyDrawable = driDestroyDrawable,
.swapBuffers = driSwapBuffers, /* swrast */
.createNewContext = driCreateNewContext, /* swrast */
.copyContext = driCopyContext,
.destroyContext = driDestroyContext,
.bindContext = driBindContext,
.unbindContext = driUnbindContext
};
/** Image driver interface */
const __DRIimageDriverExtension driImageDriverExtension = {
.base = { __DRI_IMAGE_DRIVER, 1 },
.createNewScreen2 = driCreateNewScreen2,
.createNewDrawable = driCreateNewDrawable,
.getAPIMask = driGetAPIMask,
.createContextAttribs = driCreateContextAttribs,
};
/** DRI2 interface */
const __DRIdri2Extension driDRI2Extension = {
.base = { __DRI_DRI2, 4 },
.createNewScreen = dri2CreateNewScreen,
.createNewDrawable = driCreateNewDrawable,
.createNewContext = driCreateNewContext,
.getAPIMask = driGetAPIMask,
.createNewContextForAPI = driCreateNewContextForAPI,
.allocateBuffer = dri2AllocateBuffer,
.releaseBuffer = dri2ReleaseBuffer,
.createContextAttribs = driCreateContextAttribs,
.createNewScreen2 = driCreateNewScreen2,
};
//src/gallium/frontends/dri/dri2.c
static const struct __DRIDriverVtableExtensionRec galliumdrm_vtable = {
.base = { __DRI_DRIVER_VTABLE, 1 },
.vtable = &galliumdrm_driver_api,
};
2.2 dri2_bind_extensions
我们接下来重点分析该函数:
static EGLBoolean
dri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
const struct dri2_extension_match *matches,
const __DRIextension **extensions,
bool optional)
{
int ret = EGL_TRUE;
void *field;
for (int i = 0; extensions[i]; i++) {
_eglLog(_EGL_DEBUG, "found extension `%s'", extensions[i]->name);
for (int j = 0; matches[j].name; j++) {
if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
extensions[i]->version >= matches[j].version) {
field = ((char *) dri2_dpy + matches[j].offset);
*(const __DRIextension **) field = extensions[i];
_eglLog(_EGL_INFO, "found extension %s version %d",
extensions[i]->name, extensions[i]->version);
break;
}
}
}
for (int j = 0; matches[j].name; j++) {
field = ((char *) dri2_dpy + matches[j].offset);
if (*(const __DRIextension **) field == NULL) {
if (optional) {
_eglLog(_EGL_DEBUG, "did not find optional extension %s version %d",
matches[j].name, matches[j].version);
} else {
_eglLog(_EGL_WARNING, "did not find extension %s version %d",
matches[j].name, matches[j].version);
ret = EGL_FALSE;
}
}
}
return ret;
}
我们可以理解这个函数,这个函数主要是填充dri2_egl_display中的各个extensions扩展,譬如:
//src/egl/drivers/dri2/egl_dri2.h
struct dri2_egl_display
{
...
const __DRIcoreExtension *core;
const __DRIimageDriverExtension *image_driver;
const __DRIdri2Extension *dri2;
const __DRIswrastExtension *swrast;
const __DRIkopperExtension *kopper;
const __DRI2flushExtension *flush;
const __DRI2flushControlExtension *flush_control;
const __DRItexBufferExtension *tex_buffer;
const __DRIimageExtension *image;
const __DRIrobustnessExtension *robustness;
const __DRI2configQueryExtension *config;
const __DRI2fenceExtension *fence;
const __DRI2bufferDamageExtension *buffer_damage;
const __DRI2blobExtension *blob;
const __DRI2rendererQueryExtension *rendererQuery;
const __DRI2interopExtension *interop;
const __DRIconfigOptionsExtension *configOptions;
const __DRImutableRenderBufferDriverExtension *mutable_render_buffer;
...
}
三. dri2_create_screen的实现
万里长征刚开始,到这里还只是第一步啊,得接续往下走,我们接着接续分析!
//src/egl/drivers/dri2/egl_dri2.c
dri2_create_screen(...)
dri2_dpy->dri_screen = dri2_dpy->image_driver->createNewScreen2(....)
这里的dri2_dpy->image_driver指向那里呢,这里可以在章节2.1和章节2.2找到答案,它指向了dri_util.c里面的结构体driImageDriverExtension,如下:
//src/gallium/frontends/dri/dri_util.c
/** Image driver interface */
const __DRIimageDriverExtension driImageDriverExtension = {
.base = { __DRI_IMAGE_DRIVER, 1 },
.createNewScreen2 = driCreateNewScreen2,
.createNewDrawable = driCreateNewDrawable,
.getAPIMask = driGetAPIMask,
.createContextAttribs = driCreateContextAttribs,
};
所以我们继续看driCreateNewScreen2的实现:
//src/gallium/frontends/dri/dri_util.c
driCreateNewScreen2(...)
__DRIscreen *psp
psp = calloc(1, sizeof(*psp))
psp->driver =
((__DRIDriverVtableExtension *)driver_extensions[i])->vtable;//指向galliumdrm_driver_api
psp->driver->InitScreen(psp)//这里会指向galliumdrm_driver_api中dri2_init_screen,在dri2.c中实现
我们接着来看dri2_init_screen的实现:
//src/gallium/frontends/dri/dri2.c
static const __DRIconfig **
dri2_init_screen(__DRIscreen * sPriv)
{
const __DRIconfig **configs;
struct dri_screen *screen;//各种screen开始出现
struct pipe_screen *pscreen = NULL;
screen = CALLOC_STRUCT(dri_screen);//构建一个,还没有开始初始化
screen->sPriv = sPriv;//开始指向,并赋值了
screen->fd = sPriv->fd;
sPriv->driverPrivate = (void *)screen;//相互引用
if (pipe_loader_drm_probe_fd(&screen->dev, screen->fd)) {//详见章节3.1
pscreen = pipe_loader_create_screen(screen->dev);//详见章节3.2
dri_init_options(screen);
}
dri2_init_screen_extensions(screen, pscreen, false);
configs = dri_init_screen_helper(screen, pscreen);
...
}
为了排版简介明了一些,这里我们不全部放在一个大章节里面,而是进行小章节,这样排版会更加合理看起来也更加的舒服!
3.1 pipe_loader_drm_probe_fd
我们接着继续往下分析该源码的实现:
//src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
static struct pipe_screen *
pipe_loader_drm_create_screen(struct pipe_loader_device *dev,
const struct pipe_screen_config *config, bool sw_vk)
{
struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(dev);
return ddev->dd->create_screen(ddev->fd, config);
}
static const struct pipe_loader_ops pipe_loader_drm_ops = {
.create_screen = pipe_loader_drm_create_screen,
.get_driconf = pipe_loader_drm_get_driconf,
.release = pipe_loader_drm_release
};
pipe_loader_drm_probe_fd(...)
pipe_loader_drm_probe_fd_nodup(struct pipe_loader_device **dev, int fd)
struct pipe_loader_drm_device *ddev = CALLOC_STRUCT(pipe_loader_drm_device);
ddev->base.ops = &pipe_loader_drm_ops;
ddev->fd = fd;
ddev->base.driver_name = loader_get_driver_for_fd(fd)
ddev->dd = get_driver_descriptor(ddev->base.driver_name, plib)
*dev = &ddev->base;
我们接着看get_driver_descriptor的实现,看看它究竟在干啥!
//src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
#ifdef GALLIUM_STATIC_TARGETS
static const struct drm_driver_descriptor *driver_descriptors[] = {
&i915_driver_descriptor,
&iris_driver_descriptor,
&crocus_driver_descriptor,
&nouveau_driver_descriptor,
&r300_driver_descriptor,
&r600_driver_descriptor,
&radeonsi_driver_descriptor,
&vmwgfx_driver_descriptor,
&kgsl_driver_descriptor,
&msm_driver_descriptor,
&virtio_gpu_driver_descriptor,
&v3d_driver_descriptor,
&vc4_driver_descriptor,
&panfrost_driver_descriptor,
&asahi_driver_descriptor,
&etnaviv_driver_descriptor,
&tegra_driver_descriptor,
&lima_driver_descriptor,
&zink_driver_descriptor,
&xxx_gpu_driver_descriptor,
};
#endif
static const struct drm_driver_descriptor *
get_driver_descriptor(const char *driver_name, struct util_dl_library **plib)
{
#ifdef GALLIUM_STATIC_TARGETS
for (int i = 0; i < ARRAY_SIZE(driver_descriptors); i++) {
if (strcmp(driver_descriptors[i]->driver_name, driver_name) == 0)
return driver_descriptors[i];
}
return &kmsro_driver_descriptor;
#else
...
#endif
...
}
那么这里的xxx_driver_descriptor是怎么实现的,刚开始我通过grep搜索发现只有定义,没有怎么实现。尼玛见鬼了不成,这又是套路啊,又是通过各种宏来实现的。我们看看它是怎么实现的(这里我以景嘉微的xxx_gpu为例来说明)。
//src/gallium/auxiliary/target-helpers/drm_helper.h
/**
* Instantiate a drm_driver_descriptor struct.
*/
#define DEFINE_DRM_DRIVER_DESCRIPTOR(descriptor_name, driver, _driconf, _driconf_count, func) \
const struct drm_driver_descriptor descriptor_name = { \
.driver_name = #driver, \
.driconf = _driconf, \
.driconf_count = _driconf_count, \
.create_screen = func, \
};
#define DRM_DRIVER_DESCRIPTOR(driver, driconf, driconf_count) \
DEFINE_DRM_DRIVER_DESCRIPTOR(driver##_driver_descriptor, driver, driconf, driconf_count, pipe_##driver##_create_screen)
#include "xxx_gpu/drm/xxx_gpu_drm_public.h"
static struct pipe_screen *
pipe_xxx_gpu_create_screen(int fd, const struct pipe_screen_config *config)
{
struct pipe_screen *screen;
screen = xxx_gpu_drm_create_screen(fd);
return screen ? debug_screen_wrap(screen) : NULL;
}
DRM_DRIVER_DESCRIPTOR(xxx_gpu, NULL, 0)
所以分析到这里我们获得了ddev->dd的指向,它指向了vendor实现的结构体drm_driver_descriptor。搞清楚了这个我们接着继续看 ddev->dd->create_screen的实现,它指向了pipe_xxx_gpu_create_screen,我们接着分析:
//src/gallium/auxiliary/target-helpers/drm_helper.h
static struct pipe_screen *
pipe_xxx_gpu_create_screen(int fd, const struct pipe_screen_config *config)
{
struct pipe_screen *screen;
screen = xxx_gpu_drm_create_screen(fd);//返回封装好的pipe_screen
struct xxx_gpu_winsys *ws;
ws = CALLOC_STRUCT(xxx_gpu_winsys)
ws->screen = xxx_gpu_create_screen(ws)
return ws->screen
return screen ? debug_screen_wrap(screen) : NULL;
}
3.2 pipe_loader_create_screen
分析完了pipe_loader_drm_probe_fd流程,我们接着咔咔一顿接着继续分析,pipe_loader_create_screen它会构建pipe_screen的结构体类型!
pipe_loader_create_screen(...)//src/gallium/frontends/dri/dri2.c
pipe_loader_create_screen(...)//src/gallium/auxiliary/pipe-loader/pipe_loader.c
pipe_loader_create_screen_vk(...)
dev->ops->create_screen(...)//这里的ops指向了pipe_loader_drm_ops,定义在pipe_loader_drm.c
pipe_loader_drm_create_screen(...)
ddev->dd->create_screen(...)//这里的ddev->dd指向了前面获取的结构体
pipe_xxx_gpu_create_screen(...)
到这里整个流程就基本结束了。后续如果需要查看的,可以继续dri2_init_screen研究,主要是要理清楚几个screen之间的关系!