Mesa软件框架以及重要数据结构分析
引言
Mesa的实现比较复杂,其中还有许多的数据结构之间的关系逻辑还不是很清楚。感觉分析了又没有分析一样,这里我们再理一理!
1.1 Mesa下EGL/GL核心数据结构和层级关系
MESA的核心数据结构很多很复杂,上图列举了一些核心数据结构主要强调了它们的层次关系,即上层使用下层的抽象结构(比如 函数指针调用),下层为上次做具体的实现(比如具体的函数实现),虽然是C代码但设计理念基本上与C++的继承类似(这个也是C语言实现大型代码框架的核心)。
这里的核心主要是Mesa软件EGL/GL层级的递进调用。
1.2 Mesa下核心文件和核心结构体
先从核心的几个文件入手:
- dri2.c:该文件主要定义了dri库函数的扩展的入口,和各种extensions的对接,通常会通过dlsym加载__driDriverGetExtensions_##drivername对应函数,然后通过函数指针匹配到对应的extensions进行赋值
//mesa/src/gallium/frontends/dri/dri2.c/* The extension is modified during runtime if DRI_PRIME is detected */
static const __DRIimageExtension dri2ImageExtensionTempl = {.base = { __DRI_IMAGE, 18 },.createImageFromName = dri2_create_image_from_name,.createImageFromRenderbuffer = dri2_create_image_from_renderbuffer,.destroyImage = dri2_destroy_image,.createImage = dri2_create_image,.queryImage = dri2_query_image,.dupImage = dri2_dup_image,.validateUsage = dri2_validate_usage,.createImageFromNames = dri2_from_names,.fromPlanar = dri2_from_planar,.createImageFromTexture = dri2_create_from_texture,.createImageFromFds = NULL,.createImageFromDmaBufs = NULL,.blitImage = dri2_blit_image,.getCapabilities = dri2_get_capabilities,.mapImage = dri2_map_image,.unmapImage = dri2_unmap_image,.createImageWithModifiers = NULL,.createImageFromDmaBufs2 = NULL,.createImageFromDmaBufs3 = NULL,.queryDmaBufFormats = NULL,.queryDmaBufModifiers = NULL,.queryDmaBufFormatModifierAttribs = NULL,.createImageFromRenderbuffer2 = dri2_create_image_from_renderbuffer2,
};/** Backend function init_screen.*/static const __DRIextension *dri_screen_extensions_base[] = {&driTexBufferExtension.base,&dri2FlushExtension.base,&dri2RendererQueryExtension.base,&dri2GalliumConfigQueryExtension.base,&dri2ThrottleExtension.base,&dri2FenceExtension.base,&dri2InteropExtension.base,&dri2NoErrorExtension.base,&driBlobExtension.base,
};/*** DRI driver virtual function table.** DRI versions differ in their implementation of init_screen and swap_buffers.*/
const struct __DriverAPIRec galliumdrm_driver_api = {.InitScreen = dri2_init_screen,.DestroyScreen = dri_destroy_screen,.CreateContext = dri_create_context,.DestroyContext = dri_destroy_context,.CreateBuffer = dri2_create_buffer,.DestroyBuffer = dri_destroy_buffer,.MakeCurrent = dri_make_current,.UnbindContext = dri_unbind_context,.AllocateBuffer = dri2_allocate_buffer,.ReleaseBuffer = dri2_release_buffer,
};/*** DRI driver virtual function table.** KMS/DRM version of the DriverAPI above sporting a different InitScreen* hook. The latter is used to explicitly initialise the kms_swrast driver* rather than selecting the approapriate driver as suggested by the loader.*/
const struct __DriverAPIRec dri_kms_driver_api = {.InitScreen = dri_kms_init_screen,.DestroyScreen = dri_destroy_screen,.CreateContext = dri_create_context,.DestroyContext = dri_destroy_context,.CreateBuffer = dri2_create_buffer,.DestroyBuffer = dri_destroy_buffer,.MakeCurrent = dri_make_current,.UnbindContext = dri_unbind_context,.AllocateBuffer = dri2_allocate_buffer,.ReleaseBuffer = dri2_release_buffer,
};/* This is the table of extensions that the loader will dlsym() for. */
const __DRIextension *galliumdrm_driver_extensions[] = {&driCoreExtension.base,// 它的实现在dri_util.c,并且它会被target.c调用到 &driImageDriverExtension.base,&driDRI2Extension.base,&gallium_config_options.base,NULL
};
- target.c:这个文件我们要怎么描述它的相关功能呢,我们可以理解它为dri库函数库入口,我们会在dri_load_driver函数中通过dri_open_driver打开对应的so库,然后通过dlsym加载__driDriverGetExtensions_##drivername函数,然后通过dri_bind_extensions获取对应的扩展!
//mesa/src/gallium/targets/dri/target.c//非常重要的一个宏定义
#define DEFINE_LOADER_DRM_ENTRYPOINT(drivername) \
const __DRIextension **__driDriverGetExtensions_##drivername(void); \
PUBLIC const __DRIextension **__driDriverGetExtensions_##drivername(void) \
{ \globalDriverAPI = &galliumdrm_driver_api; \return galliumdrm_driver_extensions; \
}#if defined(HAVE_LIBDRM)const __DRIextension **__driDriverGetExtensions_kms_swrast(void);//kms_swrastPUBLIC const __DRIextension **__driDriverGetExtensions_kms_swrast(void)
{LOGE("__driDriverGetExtensions_kms_swrast");globalDriverAPI = &dri_kms_driver_api;//它的实现被定义在dri2.c中return galliumdrm_driver_extensions;//它的实现被定义在Dri2.cz中
}#endif//intel I915定义
#if defined(GALLIUM_I915)
DEFINE_LOADER_DRM_ENTRYPOINT(i915)
#endif//AMD显卡dri函数入口定义
#if defined(GALLIUM_R300)
DEFINE_LOADER_DRM_ENTRYPOINT(r300)
#endif#if defined(GALLIUM_R600)
DEFINE_LOADER_DRM_ENTRYPOINT(r600)
#endif
- dri_util.c:它是dri2框架中的一个工具类,它内部实现的函数基本是前面dri2.c中扩展extensions的实现
//mesa/src/mesa/drivers/dri/common/dri_util.c/*** \file dri_util.c* DRI utility functions.** This module acts as glue between GLX and the actual hardware driver. A DRI* driver doesn't really \e have to use any of this - it's optional. But, some* useful stuff is done here that otherwise would have to be duplicated in most* drivers.* * Basically, these utility functions take care of some of the dirty details of* screen initialization, context creation, context binding, DRM setup, etc.** These functions are compiled into each DRI driver so libGL.so knows nothing* about them.* DRI实用功能* 此模块充当GLX和实际硬件驱动程序之间的粘合剂。DRI驱动程序实际上并不需要使用这些——它是可选的。* 但是,这里完成了一些有用的东西,否则将不得不在大多数驱动程序中重复。*基本上,这些实用程序函数负责屏幕初始化,上下文创建,上下文绑定,DRM设置等一些肮脏的细节。* 这些函数被编译到每个DRI驱动程序中,所以libGL。所以对他们一无所知。*//** 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
};/** 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,
};const __DRIswrastExtension driSWRastExtension = {.base = { __DRI_SWRAST, 4 },.createNewScreen = driSWRastCreateNewScreen,.createNewDrawable = driCreateNewDrawable,.createNewContextForAPI = driCreateNewContextForAPI,.createContextAttribs = driCreateContextAttribs,.createNewScreen2 = driSWRastCreateNewScreen2,
};/** Image driver interface */
const __DRIimageDriverExtension driImageDriverExtension = {.base = { __DRI_IMAGE_DRIVER, 1 },.createNewScreen2 = driCreateNewScreen2,.createNewDrawable = driCreateNewDrawable,.getAPIMask = driGetAPIMask,.createContextAttribs = driCreateContextAttribs,
};
通过我们前面的总结,我们可以看到dri的extensions的结构galliumdrm_driver_extensions定义在dri2.c中,它其中的实现在dri_util.c中
- gl_context:gl绘制上下文核心结构体
//mesa/src/mesa/main/mtypes.h
/*** Mesa rendering context.** This is the central context data structure for Mesa. Almost all* OpenGL state is contained in this structure.* Think of this as a base class from which device drivers will derive* sub classes.*/
struct gl_context
{.../*** The current dispatch table for non-displaylist-saving execution, either* BeginEnd or OutsideBeginEnd*/struct _glapi_table *Exec;... /*** Device driver function pointer table*/struct dd_function_table Driver; ...
}
- st_context:官方没有介绍,我们可以把他理解为状态上下文(state tracker context)
//src/mesa/state_tracker/st_context.h
struct st_context
{...struct gl_context *ctx;struct pipe_screen *screen;struct pipe_context *pipe;...
}//src/mesa/state_tracker/st_context.c
static void
st_init_driver_functions(struct pipe_screen *screen,struct dd_function_table *functions)
{_mesa_init_sampler_object_functions(functions);st_init_draw_functions(functions);st_init_blit_functions(functions);st_init_bufferobject_functions(screen, functions);st_init_clear_functions(functions);functions->Clear = st_Clear;st->pipe->clear(...)、、这里的pipi是pipe_context,且在lp_context中,llvmpipe->pipe.clear = llvmpipe_clear;st_init_bitmap_functions(functions);st_init_copy_image_functions(functions);st_init_drawpixels_functions(functions);st_init_rasterpos_functions(functions);st_init_drawtex_functions(functions);st_init_eglimage_functions(functions);st_init_fbo_functions(functions);
// 省略
}_mesa_Clearclear(...)ctx->Driver.Clear(...)//此处的ctx为gl_context,Driver为dd_function_table,在前面被赋值//这块怎么被调用到的详见章节3
struct st_context *
st_create_context(gl_api api, struct pipe_context *pipe,const struct gl_config *visual,struct st_context *share,const struct st_config_options *options,bool no_error)
{struct gl_context *ctx;struct gl_context *shareCtx = share ? share->ctx : NULL;struct dd_function_table funcs;struct st_context *st;util_cpu_detect();memset(&funcs, 0, sizeof(funcs));st_init_driver_functions(pipe->screen, &funcs);...
}
- pipe_context:Gallium渲染上下文
//src/gallium/include/pipe/p_context.h
/*** Gallium rendering context. Basically:* - state setting functions* - VBO drawing functions* - surface functions*/
struct pipe_context {struct pipe_screen *screen;void (*draw_vbo)(...);...
看注释,这个结构体蛮厉害的!
- dd_function_table:这个结构体,起到了承接gl_xxx—>mesa_xxx到st_xxx的作用
//src/mesa/main/dd.h
/*** Device driver function table.* Core Mesa uses these function pointers to call into device drivers.* Most of these functions directly correspond to OpenGL state commands.* Core Mesa will call these functions after error checking has been done* so that the drivers don't have to worry about error testing.** Vertex transformation/clipping/lighting is patched into the T&L module.* Rasterization functions are patched into the swrast module.** Note: when new functions are added here, the drivers/common/driverfuncs.c* file should be updated too!!!*/
struct dd_function_table {.../*** Clear the color/depth/stencil/accum buffer(s).* \param buffers a bitmask of BUFFER_BIT_* flags indicating which* renderbuffers need to be cleared.*/void (*Clear)( struct gl_context *ctx, GLbitfield buffers ); ...
}
- kms_sw_winsys:功能,通过libdrm,和内核drm交互:申请显存(也可能是内存)bo,显存map到内存,查询bo是否忙(正在被显卡使用)
- llvmpipe_screen:使用kms_swrast并且是llvmpipe做后端,接口类,功能:查询显卡特性参数。另外,注册了资源构造函数。资源指显存资源,如bo,texture,并且现了pipe_screen定义的接口其中注册了一个sw_winsys,以辅助实现pipe_screen定义的接口.screen主要体现硬件的能力,创建和管理资源
struct llvmpipe_screen
{struct pipe_screen base;struct sw_winsys *winsys;...
}
- llvmpipe_context:继承自pipe_context其中定义了和context相关的函数集context可以认为是硬件的一个pipe line的实例,涉及到state的设置,fence等
struct llvmpipe_context {struct pipe_context pipe; /**< base class */...
}
Setting rendering state (texture sampler state, blending state, rasterization state, vertex array info, drawing surfaces, etc.)
Setting shader state, using the TGSI binary shader representation.
Vertex array and indexed vertex array drawing.
- pipe_开头函数: pipe_开头的状态对象,是对现代显卡的底层抽象层,是架构无关层