天天看点

weston中panel的渲染过程

上一节最后提到过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进入循环。

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