diff options
Diffstat (limited to 'drivers/gpu/drm/qxl/qxl_draw.c')
| -rw-r--r-- | drivers/gpu/drm/qxl/qxl_draw.c | 263 | 
1 files changed, 180 insertions, 83 deletions
diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c index 3c8c3dbf9378..56e1d633875e 100644 --- a/drivers/gpu/drm/qxl/qxl_draw.c +++ b/drivers/gpu/drm/qxl/qxl_draw.c @@ -23,25 +23,29 @@  #include "qxl_drv.h"  #include "qxl_object.h" +static int alloc_clips(struct qxl_device *qdev, +		       struct qxl_release *release, +		       unsigned num_clips, +		       struct qxl_bo **clips_bo) +{ +	int size = sizeof(struct qxl_clip_rects) + sizeof(struct qxl_rect) * num_clips; + +	return qxl_alloc_bo_reserved(qdev, release, size, clips_bo); +} +  /* returns a pointer to the already allocated qxl_rect array inside   * the qxl_clip_rects. This is *not* the same as the memory allocated   * on the device, it is offset to qxl_clip_rects.chunk.data */  static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,  					      struct qxl_drawable *drawable,  					      unsigned num_clips, -					      struct qxl_bo **clips_bo, -					      struct qxl_release *release) +					      struct qxl_bo *clips_bo)  {  	struct qxl_clip_rects *dev_clips;  	int ret; -	int size = sizeof(*dev_clips) + sizeof(struct qxl_rect) * num_clips; -	ret = qxl_alloc_bo_reserved(qdev, size, clips_bo); -	if (ret) -		return NULL; -	ret = qxl_bo_kmap(*clips_bo, (void **)&dev_clips); +	ret = qxl_bo_kmap(clips_bo, (void **)&dev_clips);  	if (ret) { -		qxl_bo_unref(clips_bo);  		return NULL;  	}  	dev_clips->num_rects = num_clips; @@ -52,20 +56,34 @@ static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,  }  static int +alloc_drawable(struct qxl_device *qdev, struct qxl_release **release) +{ +	int ret; +	ret = qxl_alloc_release_reserved(qdev, sizeof(struct qxl_drawable), +					 QXL_RELEASE_DRAWABLE, release, +					 NULL); +	return ret; +} + +static void +free_drawable(struct qxl_device *qdev, struct qxl_release *release) +{ +	qxl_release_free(qdev, release); +} + +/* release needs to be reserved at this point */ +static int  make_drawable(struct qxl_device *qdev, int surface, uint8_t type,  	      const struct qxl_rect *rect, -	      struct qxl_release **release) +	      struct qxl_release *release)  {  	struct qxl_drawable *drawable; -	int i, ret; +	int i; -	ret = qxl_alloc_release_reserved(qdev, sizeof(*drawable), -					 QXL_RELEASE_DRAWABLE, release, -					 NULL); -	if (ret) -		return ret; +	drawable = (struct qxl_drawable *)qxl_release_map(qdev, release); +	if (!drawable) +		return -ENOMEM; -	drawable = (struct qxl_drawable *)qxl_release_map(qdev, *release);  	drawable->type = type;  	drawable->surface_id = surface;		/* Only primary for now */ @@ -91,14 +109,23 @@ make_drawable(struct qxl_device *qdev, int surface, uint8_t type,  		drawable->bbox = *rect;  	drawable->mm_time = qdev->rom->mm_clock; -	qxl_release_unmap(qdev, *release, &drawable->release_info); +	qxl_release_unmap(qdev, release, &drawable->release_info);  	return 0;  } -static int qxl_palette_create_1bit(struct qxl_bo **palette_bo, +static int alloc_palette_object(struct qxl_device *qdev, +				struct qxl_release *release, +				struct qxl_bo **palette_bo) +{ +	return qxl_alloc_bo_reserved(qdev, release, +				     sizeof(struct qxl_palette) + sizeof(uint32_t) * 2, +				     palette_bo); +} + +static int qxl_palette_create_1bit(struct qxl_bo *palette_bo, +				   struct qxl_release *release,  				   const struct qxl_fb_image *qxl_fb_image)  { -	struct qxl_device *qdev = qxl_fb_image->qdev;  	const struct fb_image *fb_image = &qxl_fb_image->fb_image;  	uint32_t visual = qxl_fb_image->visual;  	const uint32_t *pseudo_palette = qxl_fb_image->pseudo_palette; @@ -108,12 +135,7 @@ static int qxl_palette_create_1bit(struct qxl_bo **palette_bo,  	static uint64_t unique; /* we make no attempt to actually set this  				 * correctly globaly, since that would require  				 * tracking all of our palettes. */ - -	ret = qxl_alloc_bo_reserved(qdev, -				    sizeof(struct qxl_palette) + sizeof(uint32_t) * 2, -				    palette_bo); - -	ret = qxl_bo_kmap(*palette_bo, (void **)&pal); +	ret = qxl_bo_kmap(palette_bo, (void **)&pal);  	pal->num_ents = 2;  	pal->unique = unique++;  	if (visual == FB_VISUAL_TRUECOLOR || visual == FB_VISUAL_DIRECTCOLOR) { @@ -126,7 +148,7 @@ static int qxl_palette_create_1bit(struct qxl_bo **palette_bo,  	}  	pal->ents[0] = bgcolor;  	pal->ents[1] = fgcolor; -	qxl_bo_kunmap(*palette_bo); +	qxl_bo_kunmap(palette_bo);  	return 0;  } @@ -144,44 +166,63 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,  	const char *src = fb_image->data;  	int depth = fb_image->depth;  	struct qxl_release *release; -	struct qxl_bo *image_bo;  	struct qxl_image *image;  	int ret; - +	struct qxl_drm_image *dimage; +	struct qxl_bo *palette_bo = NULL;  	if (stride == 0)  		stride = depth * width / 8; +	ret = alloc_drawable(qdev, &release); +	if (ret) +		return; + +	ret = qxl_image_alloc_objects(qdev, release, +				      &dimage, +				      height, stride); +	if (ret) +		goto out_free_drawable; + +	if (depth == 1) { +		ret = alloc_palette_object(qdev, release, &palette_bo); +		if (ret) +			goto out_free_image; +	} + +	/* do a reservation run over all the objects we just allocated */ +	ret = qxl_release_reserve_list(release, true); +	if (ret) +		goto out_free_palette; +  	rect.left = x;  	rect.right = x + width;  	rect.top = y;  	rect.bottom = y + height; -	ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &rect, &release); -	if (ret) -		return; +	ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &rect, release); +	if (ret) { +		qxl_release_backoff_reserve_list(release); +		goto out_free_palette; +	} -	ret = qxl_image_create(qdev, release, &image_bo, -			       (const uint8_t *)src, 0, 0, -			       width, height, depth, stride); +	ret = qxl_image_init(qdev, release, dimage, +			     (const uint8_t *)src, 0, 0, +			     width, height, depth, stride);  	if (ret) { -		qxl_release_unreserve(qdev, release); +		qxl_release_backoff_reserve_list(release);  		qxl_release_free(qdev, release);  		return;  	}  	if (depth == 1) { -		struct qxl_bo *palette_bo;  		void *ptr; -		ret = qxl_palette_create_1bit(&palette_bo, qxl_fb_image); -		qxl_release_add_res(qdev, release, palette_bo); +		ret = qxl_palette_create_1bit(palette_bo, release, qxl_fb_image); -		ptr = qxl_bo_kmap_atomic_page(qdev, image_bo, 0); +		ptr = qxl_bo_kmap_atomic_page(qdev, dimage->bo, 0);  		image = ptr;  		image->u.bitmap.palette =  			qxl_bo_physical_address(qdev, palette_bo, 0); -		qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr); -		qxl_bo_unreserve(palette_bo); -		qxl_bo_unref(&palette_bo); +		qxl_bo_kunmap_atomic_page(qdev, dimage->bo, ptr);  	}  	drawable = (struct qxl_drawable *)qxl_release_map(qdev, release); @@ -199,16 +240,20 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,  	drawable->u.copy.mask.bitmap = 0;  	drawable->u.copy.src_bitmap = -		qxl_bo_physical_address(qdev, image_bo, 0); +		qxl_bo_physical_address(qdev, dimage->bo, 0);  	qxl_release_unmap(qdev, release, &drawable->release_info); -	qxl_release_add_res(qdev, release, image_bo); -	qxl_bo_unreserve(image_bo); -	qxl_bo_unref(&image_bo); - -	qxl_fence_releaseable(qdev, release);  	qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); -	qxl_release_unreserve(qdev, release); +	qxl_release_fence_buffer_objects(release); + +out_free_palette: +	if (palette_bo) +		qxl_bo_unref(&palette_bo); +out_free_image: +	qxl_image_free_objects(qdev, dimage); +out_free_drawable: +	if (ret) +		free_drawable(qdev, release);  }  /* push a draw command using the given clipping rectangles as @@ -243,10 +288,14 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,  	int depth = qxl_fb->base.bits_per_pixel;  	uint8_t *surface_base;  	struct qxl_release *release; -	struct qxl_bo *image_bo;  	struct qxl_bo *clips_bo; +	struct qxl_drm_image *dimage;  	int ret; +	ret = alloc_drawable(qdev, &release); +	if (ret) +		return; +  	left = clips->x1;  	right = clips->x2;  	top = clips->y1; @@ -263,36 +312,52 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,  	width = right - left;  	height = bottom - top; + +	ret = alloc_clips(qdev, release, num_clips, &clips_bo); +	if (ret) +		goto out_free_drawable; + +	ret = qxl_image_alloc_objects(qdev, release, +				      &dimage, +				      height, stride); +	if (ret) +		goto out_free_clips; + +	/* do a reservation run over all the objects we just allocated */ +	ret = qxl_release_reserve_list(release, true); +	if (ret) +		goto out_free_image; +  	drawable_rect.left = left;  	drawable_rect.right = right;  	drawable_rect.top = top;  	drawable_rect.bottom = bottom; +  	ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &drawable_rect, -			    &release); +			    release);  	if (ret) -		return; +		goto out_release_backoff;  	ret = qxl_bo_kmap(bo, (void **)&surface_base);  	if (ret) -		goto out_unref; +		goto out_release_backoff; -	ret = qxl_image_create(qdev, release, &image_bo, surface_base, -			       left, top, width, height, depth, stride); + +	ret = qxl_image_init(qdev, release, dimage, surface_base, +			     left, top, width, height, depth, stride);  	qxl_bo_kunmap(bo);  	if (ret) -		goto out_unref; +		goto out_release_backoff; + +	rects = drawable_set_clipping(qdev, drawable, num_clips, clips_bo); +	if (!rects) +		goto out_release_backoff; -	rects = drawable_set_clipping(qdev, drawable, num_clips, &clips_bo, release); -	if (!rects) { -		qxl_bo_unref(&image_bo); -		goto out_unref; -	}  	drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);  	drawable->clip.type = SPICE_CLIP_TYPE_RECTS;  	drawable->clip.data = qxl_bo_physical_address(qdev,  						      clips_bo, 0); -	qxl_release_add_res(qdev, release, clips_bo);  	drawable->u.copy.src_area.top = 0;  	drawable->u.copy.src_area.bottom = height; @@ -306,11 +371,9 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,  	drawable->u.copy.mask.pos.y = 0;  	drawable->u.copy.mask.bitmap = 0; -	drawable->u.copy.src_bitmap = qxl_bo_physical_address(qdev, image_bo, 0); +	drawable->u.copy.src_bitmap = qxl_bo_physical_address(qdev, dimage->bo, 0);  	qxl_release_unmap(qdev, release, &drawable->release_info); -	qxl_release_add_res(qdev, release, image_bo); -	qxl_bo_unreserve(image_bo); -	qxl_bo_unref(&image_bo); +  	clips_ptr = clips;  	for (i = 0; i < num_clips; i++, clips_ptr += inc) {  		rects[i].left   = clips_ptr->x1; @@ -319,17 +382,22 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,  		rects[i].bottom = clips_ptr->y2;  	}  	qxl_bo_kunmap(clips_bo); -	qxl_bo_unreserve(clips_bo); -	qxl_bo_unref(&clips_bo); -	qxl_fence_releaseable(qdev, release);  	qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); -	qxl_release_unreserve(qdev, release); -	return; +	qxl_release_fence_buffer_objects(release); + +out_release_backoff: +	if (ret) +		qxl_release_backoff_reserve_list(release); +out_free_image: +	qxl_image_free_objects(qdev, dimage); +out_free_clips: +	qxl_bo_unref(&clips_bo); +out_free_drawable: +	/* only free drawable on error */ +	if (ret) +		free_drawable(qdev, release); -out_unref: -	qxl_release_unreserve(qdev, release); -	qxl_release_free(qdev, release);  }  void qxl_draw_copyarea(struct qxl_device *qdev, @@ -342,22 +410,36 @@ void qxl_draw_copyarea(struct qxl_device *qdev,  	struct qxl_release *release;  	int ret; +	ret = alloc_drawable(qdev, &release); +	if (ret) +		return; + +	/* do a reservation run over all the objects we just allocated */ +	ret = qxl_release_reserve_list(release, true); +	if (ret) +		goto out_free_release; +  	rect.left = dx;  	rect.top = dy;  	rect.right = dx + width;  	rect.bottom = dy + height; -	ret = make_drawable(qdev, 0, QXL_COPY_BITS, &rect, &release); -	if (ret) -		return; +	ret = make_drawable(qdev, 0, QXL_COPY_BITS, &rect, release); +	if (ret) { +		qxl_release_backoff_reserve_list(release); +		goto out_free_release; +	}  	drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);  	drawable->u.copy_bits.src_pos.x = sx;  	drawable->u.copy_bits.src_pos.y = sy; -  	qxl_release_unmap(qdev, release, &drawable->release_info); -	qxl_fence_releaseable(qdev, release); +  	qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); -	qxl_release_unreserve(qdev, release); +	qxl_release_fence_buffer_objects(release); + +out_free_release: +	if (ret) +		free_drawable(qdev, release);  }  void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec) @@ -370,10 +452,21 @@ void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)  	struct qxl_release *release;  	int ret; -	ret = make_drawable(qdev, 0, QXL_DRAW_FILL, &rect, &release); +	ret = alloc_drawable(qdev, &release);  	if (ret)  		return; +	/* do a reservation run over all the objects we just allocated */ +	ret = qxl_release_reserve_list(release, true); +	if (ret) +		goto out_free_release; + +	ret = make_drawable(qdev, 0, QXL_DRAW_FILL, &rect, release); +	if (ret) { +		qxl_release_backoff_reserve_list(release); +		goto out_free_release; +	} +  	drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);  	drawable->u.fill.brush.type = SPICE_BRUSH_TYPE_SOLID;  	drawable->u.fill.brush.u.color = color; @@ -384,7 +477,11 @@ void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)  	drawable->u.fill.mask.bitmap = 0;  	qxl_release_unmap(qdev, release, &drawable->release_info); -	qxl_fence_releaseable(qdev, release); +  	qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); -	qxl_release_unreserve(qdev, release); +	qxl_release_fence_buffer_objects(release); + +out_free_release: +	if (ret) +		free_drawable(qdev, release);  }  | 
