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

news2024/9/22 15:35:19

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之间的关系!

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

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

相关文章

人生二选一:央企就业?美国做博士后?—请看她的抉择

一位30岁的女博士&#xff0c;收到国内央企和德国、美国的博士后邀请函&#xff0c;她该如何选择&#xff1f;知识人网小编推荐这篇文章&#xff0c;为大家解开谜题的同时&#xff0c;也给有同样纠结的学者提供一些启迪。 去年12月底的一个晚上&#xff0c;我收到美国一所高校发…

炒黄金怎么追单?-融知财经网

在黄金投资领域,当市场行情呈现出有利的走势时,许多交易者会选择追加下单以扩大盈利。追单作为一种投资策略,旨在利用市场波动获取额外收益。然而,要想在追单中取得成功,需要掌握一定的技巧和策略。融知财经网给介绍黄金交易中追单的一些关键技巧,帮助投资者理智追单,稳健获利。…

Sui生态DeFi项目Cetus和Aftermath宣布启动孵化器

Sui DeFi中的去中心化交易所Cetus和Aftermath Finance联合Sui基金会宣布启动新的孵化器&#xff0c;为初创项目提供更多可行性途径。这两个DeFi项目在Sui上有着较长的历史&#xff0c;自去年一同与主网推出以来&#xff0c;目前在TVL方面位居前五。这两个项目的持久性和成功使它…

怎么把纸质文件扫描成电子版?方法教会你!

怎么把纸质文件扫描成电子版&#xff1f;在数字化时代&#xff0c;将纸质文件转换为电子版已成为日常工作和学习的必备技能。无论是合同、证件、笔记还是其他文档&#xff0c;通过扫描软件都能轻松实现电子化&#xff0c;方便存储、查阅和分享。以下将介绍几款功能强大、操作简…

vs2019+QT扩展 定义自定义模块选择

环境&#xff1a;vs2019QT扩展&#xff08;2.63.2&#xff09; 对于我们如果想将自己的模块&#xff0c;或类似于QtXlsx这样的库直接添加到QT目录中时&#xff0c;也想可以通过选择模块自动引入头文件和库文件时&#xff0c;可以直接通过修改配置文件的方式添加到模块选择界面…

Future Marketing美妆个护品牌数字生态大会报名倒计时

/Future Marketing与创会展讯/ 由Future Marketing组委会携主办&#xff0c;广州市化妆品产业协会、深圳市跨境电子商务协会、上海日化产业协会、福建日化商会等行业协会与媒体战略联动等2024美妆个护品牌数字生态大会将于6月27日在上海举办。大会将以“夯实基础 洞见未来”为…

太速科技-16通道24bit 256kHZ 的振动信号千兆网络采集器

16通道24bit 256kHZ 的振动信号千兆网络采集器 一、产品概述 数据采集器是一台运行Linux操作系统的智能终端&#xff0c;在以太网络的支持下&#xff0c;可迅速构建起大规模的分布式智能数据采集系统。采集器终端体积小&#xff0c;功耗低&#xff0c;易集成&#xff0c…

Java-Stream流-概述、创建、使用:遍历/匹配、筛选、聚合、映射、归约、排序、提取/组合

Java8-Stream&#xff1a; 一、Stream流概述1.Stream流的特点&#xff1a;2.使用步骤&#xff1a;3.常用方法示例&#xff1a; 二、Stream流创建1.常见的创建Stream的方法2. stream()或parallelStream()方法的使用和选择 三、Stream流使用Optional案例中使用的实体类1.遍历/匹配…

c 的库函数有哪些

C语言的库函数非常丰富&#xff0c;涵盖了多种功能&#xff0c;为程序员提供了大量的工具来完成各种任务。以下是一些主要的C语言库函数及其分类&#xff1a; 标准输入输出函数&#xff1a; printf()&#xff1a;用于输出格式化的数据到标准输出设备。scanf()&#xff1a;用于…

软件需求分析和软件原型开发是一会事情吗?

软件需求分析和软件原型开发是软件开发过程中的两个重要环节&#xff0c;它们各自承担着不同的任务&#xff0c;但又紧密相连&#xff0c;共同影响着软件项目的成功。下面将详细解释这两个环节的定义、目的以及它们之间的关系。 一、软件需求分析 定义&#xff1a;软件需求分析…

display ospf routing类型字段:Transit、Stub(区域内部)与Type2

4. B 通过 display ospf routing 命令可显示本路由器中 OSPF 路由表的信息。 其中的路由条目中 &#xff0c; 包含了 到区域内与本路由器直连 (邻居 )的路由器的路由 (TypeTransit) 、 到区域内与本路由器不直连的路由器的路由 (Type-Stub) 、 到自治系统内其它区域的路由(…

99%的人都不知道,微信才是真正的学习神器

微信&#xff0c;作为一款全球最受欢迎的社交应用之一&#xff0c;除了聊天、朋友圈、小程序等功能外&#xff0c;还有许多隐藏的学习功能&#xff0c;今天小编就给大家分享10个微信隐藏的学习功能&#xff0c;助您轻松成为学霸。 1、微信笔记 用过代办清单软件的朋友都知道&…

五款局域网监控软件良心推荐

五款局域网监控软件良心推荐 有人问我&#xff0c;能不能推荐几款好用的局域网监控软件。 我说&#xff0c;当然可以了&#xff0c;凭良心说&#xff0c;这几款软件在实用性、用户体验、隐私保护以及性价比上&#xff0c;绝对是当前最强监控软件。 1. 安企神 这款软件支持7天…

鸿蒙ArkUI-X跨语言调用说明:【平台桥接(@arkui-x.bridge)】

平台桥接(arkui-x.bridge) 简介 平台桥接用于客户端&#xff08;ArkUI&#xff09;和平台&#xff08;Android或iOS&#xff09;之间传递消息&#xff0c;即用于ArkUI与平台双向数据传递、ArkUI侧调用平台的方法、平台调用ArkUI侧的方法。 以Android平台为例&#xff0c;Ark…

Scikit-Learn随机森林

Scikit-Learn随机森林 1、随机森林1.1、集成学习1.2、Bagging方法1.3、随机森林算法1.4、随机森林的优缺点2、Scikit-Learn随机森林回归2.1、Scikit-Learn随机森林回归API2.2、随机森林回归实践(加州房价预测)1、随机森林 随机森林是一种由决策树构成的集成算法,它在大多情况…

java -- jar打包成exe -- 携带jre环境

java的项目一般都是以jar发布&#xff0c;很少打包为可执行程序&#xff0c;因此常见的打包方式也不多&#xff0c;且即使打包之后也需要jre环境才能运行&#xff0c;大部分打包都不会携带jre&#xff0c;需要手动添加jre。这里介绍几种我用过的打包方案。 exe4j(不推荐) jpac…

智能视频监控技术为游泳馆安全护航,助力安全管理新升级

随着社会的进步和科技的发展&#xff0c;视频监控技术在各行各业的应用越来越广泛。游泳馆作为公共场所&#xff0c;每天都会有大量的游泳者进出。在这样的环境中&#xff0c;有时难免会发生一些意外事故&#xff0c;如溺水、摔倒等。因此&#xff0c;视频监控建设的必要性尤为…

WWW24因果论文(3/8) |通过因果干预实现图分布外泛化

【摘要】由于图神经网络 (GNN) 通常会随着分布变化而出现性能下降&#xff0c;因此分布外 (OOD) 泛化在图学习中引起了越来越多的关注。挑战在于&#xff0c;图上的分布变化涉及节点之间错综复杂的互连&#xff0c;并且数据中通常不存在环境标签。在本文中&#xff0c;我们采用…

恭喜社区迎来新PMC成员!

恭喜Apache SeaTunnel社区又迎来一位PMC Memberliugddx&#xff01;在社区持续活跃的两年间&#xff0c;大家经常看到这位开源爱好者出现在社区的各种活动中&#xff0c;为项目和社区发展添砖加瓦。如今成为项目PMC Member&#xff0c;意味着在社区中的责任更重了&#xff0c;他…

香橙派 AIpro的NPU随手记体验日记

昇腾AI 技术路线 8TOPS INT8&#xff08;FP16&#xff09;AI算力 LPDDR4X 8GB/16GB &#x1f4c5; 20240525 开放了原理图和源码&#xff0c;功能接口就不描述了手册都有描述&#xff0c;新手好好学习可以从底层覆盖到应用一个载板拿下 完成香橙派AIpro上手体验 镜像安装&am…