Android环境下Mesa初始化流程重学习之eglInitialize

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
└── vulkan29 directories, 1 filetree 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└── virgl108 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.cconst _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_PLATFORMstruct gbm_dri_device *gbm_dri;
#endifchar *driver_name;const __DRIextension **loader_extensions;const __DRIextension **driver_extensions;#ifdef HAVE_X11_PLATFORMxcb_connection_t *conn;xcb_screen_t *screen;bool swap_available;
#ifdef HAVE_DRI3bool 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_PLATFORMstruct 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_PLATFORMconst gralloc_module_t *gralloc;/* gralloc vendor usage bit for front rendering */uint32_t front_rendering_usage;
#endifbool 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_apipsp->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;//指向__DRIscreenboolean 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.cdri2_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.cstruct 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.cdri2_load_driver_common(disp, dri3_driver_extensions)extensions = dri2_open_driver(disp)//详见章节2.1dri2_bind_extensions(dri2_dpy, driver_extensions, extensions, false)//详见章节2.2dri2_dpy->driver_extensions = extensions

2.1 dri2_open_driver

我们接下来重点分析该函数:

 dri2_open_driver()//src/egl/drivers/dri2/egl_dri2.cconst 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_gpuget_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 *psppsp = calloc(1, sizeof(*psp))psp->driver =((__DRIDriverVtableExtension *)driver_extensions[i])->vtable;//指向galliumdrm_driver_apipsp->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.1pscreen = pipe_loader_create_screen(screen->dev);//详见章节3.2dri_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.cstatic 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,
};
#endifstatic const struct drm_driver_descriptor *
get_driver_descriptor(const char *driver_name, struct util_dl_library **plib)
{
#ifdef GALLIUM_STATIC_TARGETSfor (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_screenstruct xxx_gpu_winsys *ws;ws = CALLOC_STRUCT(xxx_gpu_winsys)ws->screen = xxx_gpu_create_screen(ws)return ws->screenreturn 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.cpipe_loader_create_screen(...)//src/gallium/auxiliary/pipe-loader/pipe_loader.cpipe_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之间的关系!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/18257.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常见排序算法之插入排序

目录 一、直接插入排序 1.1 什么是插入排序 1.2 代码思路 1.3 C语言源码 二、希尔排序 2.0 插入排序的弊端 2.1 什么是希尔排序&#xff1f; 2.2 排序思路 2.3 C语言源码 一、直接插入排序 1.1 什么是插入排序 插入排序是一种简单直观的排序算法&#xff0c;它通过构…

LCD屏入门(基于ESP32)

主要参考资料&#xff1a; B站【乐鑫全球开发者大会】DevCon23 #17 &#xff5c;HMI 智能屏解决方案 目录 1.LCD屏幕硬件层2.LVGL驱动层 1.LCD屏幕硬件层 MCU常用的驱动接口在下面&#xff0c;大致可以划分为串口屏和并口屏。 串口屏相较于并行屏优势是占用IO少&#xff0c;相…

【oracle】Oracle RAC中的GNS到底是什么?

本文为云贝教育 刘峰 原创&#xff0c;请尊重知识产权&#xff0c;转发请注明出处&#xff0c;不接受任何抄袭、演绎和未经注明出处的转载 一、概述 Oracle Grid Naming Service (GNS) 是Oracle Grid Infrastructure的一个重要组件&#xff0c;它提供了一种集中式的命名服务&…

[机缘参悟-191] - 《道家-水木然人间清醒1》读书笔记 -14- 关系界限 - 经济和人格上的独立,走向成熟的必经之路,才能更好的谈其他情感(IT)

目录 前言&#xff1a; 1、“友善的孤独者” 2、“外向的孤独者” 3、道不同不相为谋 4、警惕依赖 5、完整独立的个体 6、不必纠正他人的错误&#xff0c;除非他影响了你 7、不再期待别人能理解自己&#xff0c;只有高维向下兼容你的人才能理解你 8、只有高维和同频的…

ChatGPT魔法,定制个性化提示词!

扮演Prompt创作者的角色 我想让你成为我的Prompt创作者。你的目标是帮助我创建最佳的Prompt&#xff0c;这个Prompt将由 你ChatGPT使用。 你将遵循以下过程&#xff1a; 1.首先&#xff0c;你会问我Prompt是关于什么的。我会告诉你&#xff0c;但我们需要通过不断的重复来改进…

jQuery下载教程

官网&#xff1a;https://jquery.com/ ** ** 点击为压缩版本 将网站打开 界面上邮件保存为js文件即可 在html文件中引入即可 <html> <head></head> <body><script src"./js/jquery-3.6.3.js"> </script> </body> <…

JDK9-21新特性概览(持续更新)

JDK9-21新特性概览 一、JDK9新特性1.1 JEP 102: Process API Updates简介案例风险 1.2 JEP 193: Variable Handles简介案例风险 1.3 JEP 200: The Modular JDK简介案例风险 1.4 JEP 213: Milling Project Coin简介案例1.1 try-with-resources增强1.2 接口中私有方法 1.5 JEP 22…

SpringBoot实现接口防抖的几种方案,杜绝重复提交

插&#xff1a; AI时代&#xff0c;程序员或多或少要了解些人工智能&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家(前言 – 人工智能教程 ) 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家…

RK3568平台(camera篇)V4L2查询获取设置设备

一.查询设备能力VIDIOC_QUERYCAP struct v4l2_capability cap; ioctl(fd, VIDIOC_QUERYCAP, &cap) struct v4l2_capability 结构体描述了视频采集设备的 driver 信息。 struct v4l2_capability { __u8 driver[16]; // 驱动名字 __u8 card[32]; // 设备名字 __u8 bus_inf…

详解makefile中的foreach

在 Makefile 中&#xff0c;foreach 函数用于迭代处理一个以空格分隔的列表&#xff0c;并针对列表中的每个元素执行相同的操作。这个函数通常用于循环处理一组变量或文件名&#xff0c;并执行相同的规则或命令。 语法&#xff1a; makefile Copy Code $(foreach var, list, …

ThingsBoard物联网网关在智慧城市数据采集中的应用

智慧城市由监控中心、采集网关、前端采集设备、前端感应执行器组成。 为何选用ThingsBoard作为平台 监控中心为物联网平台&#xff0c;该平台包含云计算、大数据、人工智能、物联网、GIS、云安全等主要模块&#xff0c;具备数据采集、数据交换、超大规模计算、数据分析、数据应…

防火墙如何端口映射?

防火墙端口映射&#xff08;Firewall Port Mapping&#xff09;是一种网络技术&#xff0c;通过对防火墙配置进行调整&#xff0c;允许外部网络用户访问内部网络中的指定端口。该技术使得外部用户可以通过公共网络访问内部网络中的特定服务或应用程序&#xff0c;从而实现远程访…

JavaScript--作用域是什么

作用域是什么 编译原理 在传统的编译语言中&#xff0c;程序中的一段源代码在执行之前会经历三个步骤。成为编译 分词/词法分析 这个过程由字符组成的字符串分解成有意义的代码块&#xff0c;这些代码块成为词法单元。 分词和词法分析之间的主要差异在于词法单元的识别是有…

实战指南:Vue 2基座 + Vue 3 + Vite + TypeScript微前端架构实现动态菜单与登录共享

实战指南&#xff1a;Vue 2基座 Vue 3 Vite TypeScript子应用vue2微前端架构实现动态菜单与登录共享 导读&#xff1a; 在当今的前端开发中&#xff0c;微前端架构已经成为了一种流行的架构模式。本文将介绍如何结合Vue 2基座、Vue 3子应用、Vite构建工具和TypeScript语言…

基于Docker的ROS开发

本文主要介绍如何使用Docker在Windows和Linux环境中部署并使用ROS&#xff0c;通过Docker Container运行ROS&#xff0c;可以方便我们在一个本地环境中运行多个ROS版本。 更多内容&#xff0c;访问专栏目录获取实时更新。 关于ROS的版本 参考ROS1 Distribution Wiki和ROS2 Dis…

nginx源码阅读理解 [持续更新,建议关注]

文章目录 前述一、nginx 进程模型基本流程二、源码里的小点1.对字符串操作都进行了原生实现2.配置文件解析也是原生实现待续 前述 通过对 nginx 的了解和代码简单阅读&#xff0c;发现这个C代码的中间件确实存在过人之处&#xff0c;使用场景特别多&#xff0c;插件模块很丰富…

10款AI工具,让工作生活学习更高效

我看大家都推荐的差不多了&#xff0c;常见好用的PC软件就那些&#xff0c;我不想反复“咀嚼”了&#xff0c;我想另辟蹊径推荐点不一样的&#xff0c;比如10款PC端的AI网站。AI已经全方位“侵入”我们的生活&#xff0c;从AI写作到AI绘画&#xff0c;从AI视频到AI语音&#xf…

Thingsboard规则链:Switch节点详解

在物联网&#xff08;IoT&#xff09;领域&#xff0c;数据的高效处理与自动化决策是构建智能系统的核心。作为一款强大的物联网平台&#xff0c;Thingsboard通过其规则引擎为开发者提供了高度灵活的工具&#xff0c;其中Switch节点是实现消息条件路由的关键组件。本文将全方位…

【深度学习】Transformer梳理

零、前言 对于transformer&#xff0c;网上的教程使用记号、术语不一 。 最关键的一点&#xff0c;网上各种图的简化程度不一 &#xff08;画个图怎么能这么偷懒&#xff09; &#xff0c;所以我打算自己手画一次图。 看到的最和善&#xff08;但是不是那么靠谱&#xff0c;我…

黑龙江某市数字孪生地下水监测系统平台项目建设经验

项目背景 地下水是一种特殊而珍贵的资源&#xff0c;它具有不可替代性&#xff0c;与经济发展及人民生活息息相关&#xff0c;针对日趋严峻的水资源危机&#xff0c;如何合理利用有限的水资源&#xff0c;保障国民经济的可持续发展是一个迫切需要解决的问题。 黑龙江某市积极…