[PATCH 2/2] compositor-drm: don't create and destroy kms fbs on every frame

Kristian Hoegsberg hoegsberg at gmail.com
Mon Apr 30 10:06:35 PDT 2012


On Mon, Apr 30, 2012 at 01:31:29PM +0300, Ander Conselvan de Oliveira wrote:
> Use the new gbm_get/set_user_data() to reuse the kms fbs if the gbm
> surface's bo's are reused.

This doesn't look right.  drm_output_render() always allocates and
sets user data, which overwrite previously set user data.  That leaks
the KMS FB and we have to create a new one every frame.  Also, caching
the KMS FB in user data is useful for gbm bos we get from
drm_output_prepare_scanout_surface() as well.  An application may be
flipping between the same two buffers, and in that case we'll want to
reuse the KMS FBs as well.

Instead, I was thinking that we could just move the drmModeAddFB call
into a get_fb_for_bo() helper function, which would look something like this:

  data = get_user_data(bo);
  if (!data)
    return data->id;

  data = malloc(sizeof *data);
  drmModeAddFB(..., &data->id);

  set_user_data(bo, data);

  return data->id;

Kristian

> ---
>  src/compositor-drm.c |   94 +++++++++++++++++++++++++++++++++++++++----------
>  1 files changed, 75 insertions(+), 19 deletions(-)
> 
> diff --git a/src/compositor-drm.c b/src/compositor-drm.c
> index e7433f7..e9b556c 100644
> --- a/src/compositor-drm.c
> +++ b/src/compositor-drm.c
> @@ -199,12 +199,51 @@ drm_output_prepare_scanout_surface(struct drm_output *output)
>  	return 0;
>  }
>  
> +struct bo_user_data {
> +	uint32_t fb_id;
> +};
> +
> +static void
> +bo_set_fb_id(struct gbm_bo *bo, uint32_t fb_id)
> +{
> +	struct bo_user_data *user_data= gbm_bo_get_user_data(bo);
> +
> +	if (!user_data)
> +		return;
> +
> +	user_data->fb_id = fb_id;
> +}
> +
> +static uint32_t
> +bo_get_fb_id(struct gbm_bo *bo)
> +{
> +	struct bo_user_data *user_data= gbm_bo_get_user_data(bo);
> +
> +	if (user_data)
> +		return user_data->fb_id;
> +	else
> +		return 0;
> +}
> +
> +static void
> +bo_free_user_data(struct gbm_bo *bo, void *data)
> +{
> +	struct gbm_device *gbm = gbm_bo_get_device(bo);
> +	struct bo_user_data *user_data = data;
> +
> +	if (user_data->fb_id)
> +		drmModeRmFB(gbm_device_get_fd(gbm), user_data->fb_id);
> +
> +	free(data);
> +}
> +
>  static void
>  drm_output_render(struct drm_output *output, pixman_region32_t *damage)
>  {
>  	struct drm_compositor *compositor =
>  		(struct drm_compositor *) output->base.compositor;
>  	struct weston_surface *surface;
> +	struct bo_user_data *data;
>  
>  	if (!eglMakeCurrent(compositor->base.display, output->egl_surface,
>  			    output->egl_surface, compositor->base.context)) {
> @@ -223,6 +262,15 @@ drm_output_render(struct drm_output *output, pixman_region32_t *damage)
>  		fprintf(stderr, "failed to lock front buffer: %m\n");
>  		return;
>  	}
> +
> +	data = calloc(1, sizeof *data);
> +	if (!data) {
> +		gbm_surface_release_buffer(output->surface, output->next_bo);
> +		output->next_bo = NULL;
> +		return;
> +	}
> +
> +	gbm_bo_set_user_data(output->next_bo, data, bo_free_user_data);
>  }
>  
>  static void
> @@ -241,6 +289,8 @@ drm_output_repaint(struct weston_output *output_base,
>  	if (!output->next_bo)
>  		drm_output_render(output, damage);
>  
> +	output->next_fb_id = bo_get_fb_id(output->next_bo);
> +
>  	stride = gbm_bo_get_pitch(output->next_bo);
>  	handle = gbm_bo_get_handle(output->next_bo).u32;
>  
> @@ -252,15 +302,20 @@ drm_output_repaint(struct weston_output *output_base,
>  		output->next_bo = NULL;
>  	}
>  
> -	ret = drmModeAddFB(compositor->drm.fd,
> -			   output->base.current->width,
> -			   output->base.current->height,
> -			   24, 32, stride, handle, &output->next_fb_id);
> -	if (ret) {
> -		fprintf(stderr, "failed to create kms fb: %m\n");
> -		gbm_surface_release_buffer(output->surface, output->next_bo);
> -		output->next_bo = NULL;
> -		return;
> +	if (!output->next_fb_id) {
> +		ret = drmModeAddFB(compositor->drm.fd,
> +				   output->base.current->width,
> +				   output->base.current->height,
> +				   24, 32, stride, handle, &output->next_fb_id);
> +		if (ret) {
> +			fprintf(stderr, "failed to create kms fb: %m\n");
> +			gbm_surface_release_buffer(output->surface, output->next_bo);
> +			output->next_bo = NULL;
> +			return;
> +		}
> +
> +		if (output->next_bo)
> +			bo_set_fb_id(output->next_bo, output->next_fb_id);
>  	}
>  
>  	mode = container_of(output->base.current, struct drm_mode, base);
> @@ -355,22 +410,23 @@ page_flip_handler(int fd, unsigned int frame,
>  		(struct drm_compositor *) output->base.compositor;
>  	uint32_t msecs;
>  
> -	if (output->current_fb_id)
> -		drmModeRmFB(c->drm.fd, output->current_fb_id);
> -	output->current_fb_id = output->next_fb_id;
> -	output->next_fb_id = 0;
> -
> -	if (output->scanout_buffer) {
> -		weston_buffer_post_release(output->scanout_buffer);
> -		wl_list_remove(&output->scanout_buffer_destroy_listener.link);
> -		output->scanout_buffer = NULL;
> -	} else if (output->current_bo) {
> +	if (output->current_bo) {
>  		gbm_surface_release_buffer(output->surface,
>  					   output->current_bo);
> +	} else {
> +		if (output->scanout_buffer) {
> +			weston_buffer_post_release(output->scanout_buffer);
> +			wl_list_remove(&output->scanout_buffer_destroy_listener.link);
> +			output->scanout_buffer = NULL;
> +		}
> +		if (output->current_fb_id)
> +			drmModeRmFB(c->drm.fd, output->current_fb_id);
>  	}
>  
>  	output->current_bo = output->next_bo;
>  	output->next_bo = NULL;
> +	output->current_fb_id = output->next_fb_id;
> +	output->next_fb_id = 0;
>  
>  	if (output->pending_scanout_buffer) {
>  		output->scanout_buffer = output->pending_scanout_buffer;
> -- 
> 1.7.4.1
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list