上一节最后提到过output_init时会将output以及surface传给server端的shell.c
struct weston_surface {
struct wl_resource *resource;
struct wl_signal destroy_signal; /* callback argument: this surface */
struct weston_compositor *compositor;
struct wl_signal commit_signal;
/** Damage in local coordinates from the client, for tex upload. */
pixman_region32_t damage;
pixman_region32_t opaque; /* part of geometry, see below */
pixman_region32_t input;
int32_t width, height;
int32_t ref_count;
/* Not for long-term storage. This exists for book-keeping while
* iterating over surfaces and views
*/
bool touched;
void *renderer_state;
struct wl_list views;
/*
* Which output to vsync this surface to.
* Used to determine whether to send or queue frame events, and for
* other client-visible syncing/throttling tied to the output
* repaint cycle.
*/
struct weston_output *output;
/*
* A more complete representation of all outputs this surface is
* displayed on.
*/
uint32_t output_mask;
struct wl_list frame_callback_list;
struct wl_list feedback_list;
struct weston_buffer_reference buffer_ref;
struct weston_buffer_viewport buffer_viewport;
int32_t width_from_buffer; /* before applying viewport */
int32_t height_from_buffer;
bool keep_buffer; /* for backends to prevent early release */
/* wp_viewport resource for this surface */
struct wl_resource *viewport_resource;
/* All the pending state, that wl_surface.commit will apply. */
struct weston_surface_state pending;
/* Matrices representing of the full transformation between
* buffer and surface coordinates. These matrices are updated
* using the weston_surface_build_buffer_matrix function. */
struct weston_matrix buffer_to_surface_matrix;
struct weston_matrix surface_to_buffer_matrix;
/*
* If non-NULL, this function will be called on
* wl_surface::commit after a new buffer has been set up for
* this surface. The integer params are the sx and sy
* parameters supplied to wl_surface::attach.
*/
void (*committed)(struct weston_surface *es, int32_t sx, int32_t sy);
void *committed_private;
int (*get_label)(struct weston_surface *surface, char *buf, size_t len);
/* Parent's list of its sub-surfaces, weston_subsurface:parent_link.
* Contains also the parent itself as a dummy weston_subsurface,
* if the list is not empty.
*/
struct wl_list subsurface_list; /* weston_subsurface::parent_link */
struct wl_list subsurface_list_pending; /* ...::parent_link_pending */
/*
* For tracking protocol role assignments. Different roles may
* have the same configure hook, e.g. in shell.c. Configure hook
* may get reset, this will not.
* XXX: map configure functions 1:1 to roles, and never reset it,
* and replace role_name with configure.
*/
const char *role_name;
bool is_mapped;
bool is_opaque;
/* An list of per seat pointer constraints. */
struct wl_list pointer_constraints;
/* zwp_surface_synchronization_v1 resource for this surface */
struct wl_resource *synchronization_resource;
int acquire_fence_fd;
struct weston_buffer_release_reference buffer_release_ref;
enum weston_hdcp_protection desired_protection;
enum weston_hdcp_protection current_protection;
enum weston_surface_protection_mode protection_mode;
};
struct wl_surface *surface;
if (desktop->want_panel) {
output->panel = panel_create(desktop, output);
surface = window_get_wl_surface(output->panel->window);
weston_desktop_shell_set_panel(desktop->shell,
output->output, surface);
}
1.compositor的render设置(gl-render)
在drm后端初始化时,会根据config选择使用pixman渲染还是opengl渲染,这里默认使用gl。
drm_backend_create
->init_egl
->drm_backend_create_gl_renderer(设置GBM参数)
->gl_renderer->display_create
->gl_renderer_display_create(egl环境创建,shader初始化)
->设置read_pixels,repaint_output,flush_damage,attach,surface_set_color,surface_get_content_size,surface_copy_content。import_dmabuf
wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YUV420);
wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_NV12);
wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YUYV);
wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_XYUV8888);
在创建surface时会调用gl-render的函数。例如wl_resource_set_implementation(设置attach/damage/frame/commit/flush接口实现函数)
static const struct wl_surface_interface surface_interface = {
surface_destroy,
surface_attach,
surface_damage,
surface_frame,
surface_set_opaque_region,
surface_set_input_region,
surface_commit,
surface_set_buffer_transform,
surface_set_buffer_scale,
surface_damage_buffer
};
attach函数:surface->compositor->renderer->attach(surface, buffer)
flush函数:surface->compositor->renderer->flush_damage(surface)
weston_surface_set_color:surface->compositor->renderer->surface_set_color(surface, red, green, blue, alpha)
2.surface创建流程
panel_create
->window_create_custom
->window_create_internal
->surface_create(window)
->wl_compositor_create_surface
->compositor_create_surface(libweston/compositor.c)
->wl_resource_set_implementation(设置attach/damage/frame/commit接口实现函数)
->wl_signal_emit(&ec->create_surface_signal, surface);//给compositor发送创建surface的信号
->weston_surface_create
->weston_surface_state_init
surface的创建最终调用到了compositor,weston_surface_create负责创建surface。主要实现逻辑如下:
weston_surface_state_init(&surface->pending)//设置当前surface为pending状态
pixman_region32_init(&surface->damage)
pixman_region32_init(&surface->opaque)
region_init_infinite(&surface->input)
主要是client请求在server端创建一个surface
3.attach到surface
刚才surface已经创建好了,然后我们需要绘制这个surface,往里面填显示数据。panel_create中在创建surface之后绑定了panel_redraw_handler。cairo_paint是渲染并合成输出的关键函数。
static void
panel_redraw_handler(struct widget *widget, void *data)
{
cairo_surface_t *surface;
cairo_t *cr;
struct panel *panel = data;
//创建一个cairo画布
cr = widget_cairo_create(panel->widget);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
set_hex_color(cr, panel->color);
//拿到cairo surface后进行绘渲染合成输出
cairo_paint(cr);
cairo_destroy(cr);
//获取surface然后销毁
surface = window_get_surface(panel->window);
cairo_surface_destroy(surface);
panel->painted = 1;
check_desktop_ready(panel->window);
}
widget_cairo_create调用逻辑
widget_cairo_create
->widget_get_cairo_surface
->window_create_main_surface
->surface_create_surface(两种surface创建方式,EGL/SHM)
->egl_window_surface_create
->//这里panel创建不会用到
->surface->toysurface=shm_surface_create//共享内存的方式进行创建,主要是设置了shm一些功能函数prepare,swap,acquire,release
->surface->toysurface->prepare
->display_create_shm_surface//创建共享内存
->shm_pool_create//os_create_anonymous_file && mmap&&wl_shm_create_pool
->display_create_shm_surface_from_pool//最重要的填充数据
->shm_pool_allocate//从池中分配空间
->cairo_image_surface_create_for_data
->wl_shm_pool_create_buffer
->surface_create_surface
surface_redraw->frame_callback
->window_schedule_redraw_task
->idle_redraw
window_schedule_resize时也会调用window_schedule_redraw
4.cairo_paint流程分析
cairo_paint会调用backend中的paint()接口
cairo_paint(cr)
->cr->backend->paint (cr)
->_cairo_default_context_paint
->_cairo_gstate_paint
->_cairo_surface_paint
->_cairo_gl_surface_paint(opengl作为后端)
->_cairo_compositor_paint
->_cairo_spans_compositor_paint() // Spans合成器(看似默认的合成器)情况下对应的paint接口
->clip_and_composite_boxes() // 将要绘制的窗口转换成一个box的集合,然后绘制所有的box
->composite_boxes() //绘制boxes
->emit_aligned_boxes()
->_cairo_gl_composite_emit_rect()
->_cairo_gl_composite_flush() //触发flush操作,将缓冲区中的数据绘制到窗口上。这里很关键,后面再详述
->_cairo_gl_composite_draw_triangles_with_clip_region() or _cairo_gl_composite_draw_tristrip() //绘制一个个矩形区域或者tristrip区域
->_cairo_gl_composite_draw_triangles // 绘制矩形
->glDrawArrays() // 调用OpenGL接口,执行实际的绘制操作。
5.display_run
上面surface已经初始化完成,display_run进入循环。
在display_create的时候,设置了display_run时的事件处理函数handle_display_data,创建鼠标和窗口主题。添加registry_listener监听。
panel_configure
->window_schedule_resize
->window_schedule_redraw
->window_schedule_redraw_task
->window->redraw_task.run = idle_redraw
->display_defer(window->display, &window->redraw_task)//将idle_redraw写入task.run
display_run
->task->run//循环一次运行一次task
idle_redraw
->surface_redraw
->surface->frame_cb = wl_surface_frame(surface->surface)//帧回调继续插入redraw任务
->widget_redraw
->panel_redraw_handler//回调进client
->cairo_paint(cr)//画图
//画完flush
->window_flush->surface_flush->shm_surface_swap
->wl_surface_attach//设置buffer
->wl_surface_damage
->wl_surface_commit
上面是整个任务栏的绘制过程,不包括launcher图标的绘制。
欢迎关注【求密勒实验室】