[Spice-devel] [PATCH 9/9] qxl: abstract object allocation away from surface/image/cursor code

Alon Levy alevy at redhat.com
Tue Feb 26 09:07:05 PST 2013


On Tue, Feb 26, 2013 at 02:32:12PM +1000, Dave Airlie wrote:

ACK all the patches above, ACK this one too with small nit picks.

Did not break xspice :)

Regarding application of patches - I had to manually merge but the
merges were the trivial ones so probably some whitespace? so if you
manage to push then it is fine.

> This abstracts the object bo/surface allocation away from the user code.
> 
> The idea is we can then plug in a KMS backend for this abstraction and mostly
> keep the surrounding code intact.
> 
> This is probably the biggest change to the driver in terms of impact of KMS
> code on UMS code. At the moment I'm storing linked list of bos for release
> handling, and that might be better done with a different data structure,
> since we are looking them up by phy_addr, either a hash table or some sort
> of rb tree perhaps, rather than a linear search.
> 
> This commit also starts usign the xorg list macros, which may require
> some compat code to work in history.
> 
> Signed-off-by: Dave Airlie <airlied at redhat.com>
> ---
>  src/qxl.h         |  52 +++++++--
>  src/qxl_cursor.c  |  52 +++++----
>  src/qxl_driver.c  |   8 +-
>  src/qxl_image.c   |  69 +++++++----
>  src/qxl_mem.c     | 343 +++++++++++++++++++++++++++++++++++++++++++++++++-----
>  src/qxl_surface.c | 302 +++++++++++++++++++++++++----------------------
>  src/qxl_surface.h |   4 +-
>  src/qxl_uxa.c     |   6 +-
>  8 files changed, 605 insertions(+), 231 deletions(-)
> 
> diff --git a/src/qxl.h b/src/qxl.h
> index 2d1840a..9eb249c 100644
> --- a/src/qxl.h
> +++ b/src/qxl.h
> @@ -45,6 +45,7 @@
>  #include "micmap.h"
>  #include "uxa/uxa.h"
>  
> +#include "list.h"
>  #ifndef XSPICE
>  #ifdef XSERVER_PCIACCESS
>  #include "pciaccess.h"
> @@ -139,6 +140,42 @@ enum {
>      QXL_DEVICE_PRIMARY_CREATED,
>  };
>  
> +struct qxl_bo;
> +/*
> + * for relocations
> + * dst_bo + dst_offset are the bo and offset into it the reloc is being written,
s/it/which/

> + * src_bo is the bo who's offset is being relocated.
> + */
> +struct qxl_bo_funcs {
> +    struct qxl_bo *(*bo_alloc)(qxl_screen_t *qxl, unsigned long size, const char *name);
> +    struct qxl_bo *(*cmd_alloc)(qxl_screen_t *qxl, unsigned long size, const char *name);
> +    void *(*bo_map)(struct qxl_bo *bo);
> +    void (*bo_unmap)(struct qxl_bo *bo);
> +    void (*bo_decref)(qxl_screen_t *qxl, struct qxl_bo *bo);
> +    void (*bo_incref)(qxl_screen_t *qxl, struct qxl_bo *bo);
> +    void (*bo_output_bo_reloc)(qxl_screen_t *qxl, uint32_t dst_offset,
> +			       struct qxl_bo *dst_bo, struct qxl_bo *src_bo);
> +    void (*write_command)(qxl_screen_t *qxl, uint32_t type, struct qxl_bo *bo);
> +    void (*update_area)(qxl_surface_t *surf, int x1, int y1, int x2, int y2);
> +    struct qxl_bo *(*create_primary)(qxl_screen_t *qxl, uint32_t width, uint32_t height, int32_t stride, uint32_t format);
> +    void (*destroy_primary)(qxl_screen_t *qxl, struct qxl_bo *primary_bo);
> +
> +    qxl_surface_t *(*create_surface)(qxl_screen_t *qxl, int width,
> +				     int height, int bpp);
> +    void (*destroy_surface)(qxl_surface_t *surf);
> +
> +    void (*bo_output_surf_reloc)(qxl_screen_t *qxl, uint32_t dst_offset,
> +				 struct qxl_bo *dst_bo,
> +				 qxl_surface_t *surf);
> +  /* surface create / destroy */
> +};
> +    
> +void qxl_ums_setup_funcs(qxl_screen_t *qxl);
> +
> +/* ums specific functions */
> +struct qxl_bo *qxl_ums_surf_mem_alloc(qxl_screen_t *qxl, uint32_t size);
> +struct qxl_bo *qxl_ums_lookup_phy_addr(qxl_screen_t *qxl, uint64_t phy_addr);
> +
>  struct _qxl_screen_t
>  {
>      /* These are the names QXL uses */
> @@ -153,7 +190,7 @@ struct _qxl_screen_t
>      struct qxl_ring *		release_ring;
>  
>      int                         device_primary;
> -    
> +    struct qxl_bo *             primary_bo;
>      int				num_modes;
>      struct QXLMode *		modes;
>      int				io_base;
> @@ -268,6 +305,9 @@ struct _qxl_screen_t
>  
>      uint32_t           deferred_fps;
>  #endif /* XSPICE */
> +
> +    struct xorg_list ums_bos;
> +    struct qxl_bo_funcs *bo_funcs;
>  };
>  
>  typedef struct qxl_output_private {
> @@ -461,7 +501,7 @@ void qxl_allocate_monitors_config (qxl_screen_t *qxl);
>  /*
>   * Images
>   */
> -struct QXLImage *qxl_image_create     (qxl_screen_t           *qxl,
> +struct qxl_bo *qxl_image_create     (qxl_screen_t           *qxl,
>  				       const uint8_t          *data,
>  				       int                     x,
>  				       int                     y,
> @@ -471,7 +511,7 @@ struct QXLImage *qxl_image_create     (qxl_screen_t           *qxl,
>  				       int                     Bpp,
>  				       Bool		       fallback);
>  void              qxl_image_destroy    (qxl_screen_t           *qxl,
> -					struct QXLImage       *image);
> +				        struct qxl_bo *bo);
>  void		  qxl_drop_image_cache (qxl_screen_t	       *qxl);
>  
>  
> @@ -484,12 +524,6 @@ struct qxl_mem *  qxl_mem_create       (void                   *base,
>  					unsigned long           n_bytes);
>  void              qxl_mem_dump_stats   (struct qxl_mem         *mem,
>  					const char             *header);
> -void *            qxl_alloc            (struct qxl_mem         *mem,
> -					unsigned long           n_bytes,
> -					const char *            name);
> -void              qxl_free             (struct qxl_mem         *mem,
> -					void                   *d,
> -					const char *            name);
>  void              qxl_mem_free_all     (struct qxl_mem         *mem);
>  void *            qxl_allocnf          (qxl_screen_t           *qxl,
>  					unsigned long           size,
> diff --git a/src/qxl_cursor.c b/src/qxl_cursor.c
> index 459cbd7..d246594 100644
> --- a/src/qxl_cursor.c
> +++ b/src/qxl_cursor.c
> @@ -32,36 +32,29 @@
>  #include <cursorstr.h>
>  
>  static void
> -push_cursor (qxl_screen_t *qxl, struct QXLCursorCmd *cursor)
> +push_cursor (qxl_screen_t *qxl, struct qxl_bo *cursor_bo)
>  {
> -    struct QXLCommand cmd;
> -
> -    /* See comment on push_command() in qxl_driver.c */
> -    if (qxl->pScrn->vtSema)
> -    {
> -        cmd.type = QXL_CMD_CURSOR;
> -        cmd.data = physical_address (qxl, cursor, qxl->main_mem_slot);
> -      
> -        qxl_ring_push (qxl->cursor_ring, &cmd);
> -    }
> +    qxl->bo_funcs->write_command (qxl, QXL_CMD_CURSOR, cursor_bo);
>  }
>  
> -static struct QXLCursorCmd *
> +static struct qxl_bo *
>  qxl_alloc_cursor_cmd(qxl_screen_t *qxl)
>  {
> -    struct QXLCursorCmd *cmd =
> -	qxl_allocnf (qxl, sizeof(struct QXLCursorCmd), "cursor command");
> +    struct qxl_bo *bo = qxl->bo_funcs->cmd_alloc (qxl, sizeof(struct QXLCursorCmd), "cursor command");
> +    struct QXLCursorCmd *cmd = qxl->bo_funcs->bo_map(bo);
>  
> -    cmd->release_info.id = pointer_to_u64 (cmd) | 1;
> +    cmd->release_info.id = pointer_to_u64 (bo) | 1;
>      
> -    return cmd;
> +    qxl->bo_funcs->bo_unmap(bo);
> +    return bo;
>  }
>  
>  static void
>  qxl_set_cursor_position(ScrnInfoPtr pScrn, int x, int y)
>  {
>      qxl_screen_t *qxl = pScrn->driverPrivate;
> -    struct QXLCursorCmd *cmd = qxl_alloc_cursor_cmd(qxl);
> +    struct qxl_bo *cmd_bo = qxl_alloc_cursor_cmd(qxl);
> +    struct QXLCursorCmd *cmd = qxl->bo_funcs->bo_map(cmd_bo);
>  
>      qxl->cur_x = x;
>      qxl->cur_y = y;
> @@ -70,7 +63,8 @@ qxl_set_cursor_position(ScrnInfoPtr pScrn, int x, int y)
>      cmd->u.position.x = qxl->cur_x + qxl->hot_x;
>      cmd->u.position.y = qxl->cur_y + qxl->hot_y;
>      
> -    push_cursor(qxl, cmd);
> +    qxl->bo_funcs->bo_unmap(cmd_bo);
> +    push_cursor(qxl, cmd_bo);
>  }
>  
>  static void
> @@ -92,9 +86,10 @@ qxl_load_cursor_argb (ScrnInfoPtr pScrn, CursorPtr pCurs)
>      int h = pCurs->bits->height;
>      int size = w * h * sizeof (CARD32);
>  
> -    struct QXLCursorCmd *cmd = qxl_alloc_cursor_cmd (qxl);
> -    struct QXLCursor *cursor =
> -	qxl_allocnf(qxl, sizeof(struct QXLCursor) + size, "cursor data");
> +    struct qxl_bo *cmd_bo = qxl_alloc_cursor_cmd(qxl);
> +    struct QXLCursorCmd *cmd;
> +    struct qxl_bo *cursor_bo = qxl->bo_funcs->bo_alloc(qxl, sizeof(struct QXLCursor) + size, "cursor data");
> +    struct QXLCursor *cursor = qxl->bo_funcs->bo_map(cursor_bo);
>  
>      cursor->header.unique = 0;
>      cursor->header.type = SPICE_CURSOR_TYPE_ALPHA;
> @@ -128,16 +123,21 @@ qxl_load_cursor_argb (ScrnInfoPtr pScrn, CursorPtr pCurs)
>      }
>  #endif
>  
> +    qxl->bo_funcs->bo_unmap(cursor_bo);
> +
>      qxl->hot_x = pCurs->bits->xhot;
>      qxl->hot_y = pCurs->bits->yhot;
>      
> +    cmd = qxl->bo_funcs->bo_map(cmd_bo);
>      cmd->type = QXL_CURSOR_SET;
>      cmd->u.set.position.x = qxl->cur_x + qxl->hot_x;
>      cmd->u.set.position.y = qxl->cur_y + qxl->hot_y;
> -    cmd->u.set.shape = physical_address (qxl, cursor, qxl->main_mem_slot);
> +    qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(struct QXLCursorCmd, u.set.shape), cmd_bo, cursor_bo);
> +
>      cmd->u.set.visible = TRUE;
> +    qxl->bo_funcs->bo_unmap(cmd_bo);
>  
> -    push_cursor(qxl, cmd);
> +    push_cursor(qxl, cmd_bo);
>  }    
>  
>  static Bool
> @@ -159,11 +159,13 @@ static void
>  qxl_hide_cursor(ScrnInfoPtr pScrn)
>  {
>      qxl_screen_t *qxl = pScrn->driverPrivate;
> -    struct QXLCursorCmd *cursor = qxl_alloc_cursor_cmd(qxl);
> +    struct qxl_bo *cmd_bo = qxl_alloc_cursor_cmd(qxl);
> +    struct QXLCursorCmd *cursor = qxl->bo_funcs->bo_map(cmd_bo);
>  
>      cursor->type = QXL_CURSOR_HIDE;
>  
> -    push_cursor(qxl, cursor);
> +    qxl->bo_funcs->bo_unmap(cmd_bo);
> +    push_cursor(qxl, cmd_bo);
>  }
>  
>  static void
> diff --git a/src/qxl_driver.c b/src/qxl_driver.c
> index 21bac83..b2f803b 100644
> --- a/src/qxl_driver.c
> +++ b/src/qxl_driver.c
> @@ -523,7 +523,7 @@ qxl_resize_primary_to_virtual (qxl_screen_t *qxl)
>      {
>  	qxl_surface_kill (qxl->primary);
>  	qxl_surface_cache_sanity_check (qxl->surface_cache);
> -	qxl_io_destroy_primary (qxl);
> +	qxl->bo_funcs->destroy_primary(qxl, qxl->primary_bo);
>      }
>      
>      qxl->primary = qxl_create_primary(qxl);
> @@ -1034,7 +1034,9 @@ qxl_pre_init (ScrnInfoPtr pScrn, int flags)
>      qxl->pScrn = pScrn;
>      qxl->x_modes = NULL;
>      qxl->entity = xf86GetEntityInfo (pScrn->entityList[0]);
> -    
> +
> +    xorg_list_init(&qxl->ums_bos);
> +
>  #ifndef XSPICE
>      qxl->pci = xf86GetPciInfoForEntity (qxl->entity->index);
>  #ifndef XSERVER_LIBPCIACCESS
> @@ -1047,6 +1049,8 @@ qxl_pre_init (ScrnInfoPtr pScrn, int flags)
>  #endif /* XSPICE */
>      pScrn->monitor = pScrn->confScreen->monitor;
>  
> +    qxl_ums_setup_funcs(qxl);
> +
>      if (!qxl_pre_init_common(pScrn))
>  	goto out;
>  
> diff --git a/src/qxl_image.c b/src/qxl_image.c
> index fcecf8a..85e2455 100644
> --- a/src/qxl_image.c
> +++ b/src/qxl_image.c
> @@ -128,7 +128,7 @@ remove_image_info (image_info_t *info)
>  #define MAX(a,b)  (((a) > (b))? (a) : (b))
>  #define MIN(a,b)  (((a) < (b))? (a) : (b))
>  
> -struct QXLImage *
> +struct qxl_bo *
>  qxl_image_create (qxl_screen_t *qxl, const uint8_t *data,
>  		  int x, int y, int width, int height,
>  		  int stride, int Bpp, Bool fallback)
> @@ -136,8 +136,9 @@ qxl_image_create (qxl_screen_t *qxl, const uint8_t *data,
>  	uint32_t hash;
>  	image_info_t *info;
>  	struct QXLImage *image;
> -	struct QXLDataChunk *head;
> +	struct qxl_bo *head_bo, *tail_bo;
>  	struct QXLDataChunk *tail;
> +	struct qxl_bo *image_bo;
>  	int dest_stride = (width * Bpp + 3) & (~3);
>  	int h;
>  
> @@ -151,7 +152,7 @@ qxl_image_create (qxl_screen_t *qxl, const uint8_t *data,
>  
>  	/* FIXME: Check integer overflow */
>  
> -	head = tail = NULL;
> +	head_bo = tail_bo = NULL;
>  
>  	hash = 0;
>  	h = height;
> @@ -159,35 +160,42 @@ qxl_image_create (qxl_screen_t *qxl, const uint8_t *data,
>  	{
>  	    int chunk_size = MAX (512 * 512, dest_stride);
>  	    int n_lines = MIN ((chunk_size / dest_stride), h);
> -	    QXLDataChunk *chunk =
> -		qxl_allocnf (qxl, sizeof *chunk + n_lines * dest_stride, "image data");
> +	    struct qxl_bo *bo = qxl->bo_funcs->bo_alloc (qxl, sizeof (QXLDataChunk) + n_lines * dest_stride, "image data");
>  
> +	    QXLDataChunk *chunk = qxl->bo_funcs->bo_map(bo);
>  	    chunk->data_size = n_lines * dest_stride;
>  	    hash = hash_and_copy (data, stride,
>  				  chunk->data, dest_stride,
>  				  Bpp, width, n_lines, hash);
>  	    
> -	    if (tail)
> +	    if (tail_bo)
>  	    {
> -		tail->next_chunk = physical_address (qxl, chunk, qxl->main_mem_slot);
> -		chunk->prev_chunk = physical_address (qxl, tail, qxl->main_mem_slot);
> +		qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDataChunk, next_chunk),
> +					       tail_bo, bo);
> +		qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDataChunk, prev_chunk),
> +					       bo, tail_bo);
> +
>  		chunk->next_chunk = 0;
>  		
> -		tail = chunk;
> +		tail_bo = bo;
>  	    }
>  	    else
>  	    {
> -		head = tail = chunk;
> +		head_bo = tail_bo = bo;
>  		chunk->next_chunk = 0;
>  		chunk->prev_chunk = 0;
>  	    }
>  
> +	    qxl->bo_funcs->bo_unmap(bo);
> +	    if (bo != head_bo)
> +		qxl->bo_funcs->bo_decref(qxl, bo);
>  	    data += n_lines * stride;
>  	    h -= n_lines;
>  	}
>  
>  	/* Image */
> -	image = qxl_allocnf (qxl, sizeof *image, "image struct");
> +	image_bo = qxl->bo_funcs->bo_alloc (qxl, sizeof *image, "image struct");
> +	image = qxl->bo_funcs->bo_map(image_bo);
>  
>  	image->descriptor.id = 0;
>  	image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
> @@ -218,8 +226,10 @@ qxl_image_create (qxl_screen_t *qxl, const uint8_t *data,
>  	image->bitmap.y = height;
>  	image->bitmap.stride = dest_stride;
>  	image->bitmap.palette = 0;
> -	image->bitmap.data = physical_address (qxl, head, qxl->main_mem_slot);
> +	qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLImage, bitmap.data),
> +				       image_bo, head_bo);
>  
> +	qxl->bo_funcs->bo_decref(qxl, head_bo);
>  	/* Add to hash table if caching is enabled */
>  	if ((fallback && qxl->enable_fallback_cache)	||
>  	    (!fallback && qxl->enable_image_cache))
> @@ -238,20 +248,24 @@ qxl_image_create (qxl_screen_t *qxl, const uint8_t *data,
>  	    }
>  	}
>  
> -	return image;
> +	qxl->bo_funcs->bo_unmap(image_bo);
> +	return image_bo;
>  }
>  
>  void
>  qxl_image_destroy (qxl_screen_t *qxl,
> -		   struct QXLImage *image)
> +		   struct qxl_bo *image_bo)
>  {
> +    struct QXLImage *image;
> +
>      image_info_t *info;
> -    uint64_t chunk;
> +    uint64_t chunk, prev_chunk;
>  
> +    image = qxl->bo_funcs->bo_map(image_bo);
>      info = lookup_image_info (image->descriptor.id,
>  			      image->descriptor.width,
>  			      image->descriptor.height);
> -
> +    qxl->bo_funcs->bo_unmap(image_bo);
>      if (info && info->image == image)
>      {
>  	--info->ref_count;
> @@ -266,20 +280,29 @@ qxl_image_destroy (qxl_screen_t *qxl,
>  	remove_image_info (info);
>      }
>  
> -    
> +    image = qxl->bo_funcs->bo_map(image_bo);
>      chunk = image->bitmap.data;
>      while (chunk)
>      {
> +	struct qxl_bo *bo;
>  	struct QXLDataChunk *virtual;
>  
> -	virtual = virtual_address (qxl, u64_to_pointer (chunk), qxl->main_mem_slot);
> -
> +	bo = qxl_ums_lookup_phy_addr(qxl, chunk);
> +	assert(bo);
> +	virtual = qxl->bo_funcs->bo_map(bo);
>  	chunk = virtual->next_chunk;
> -
> -	qxl_free (qxl->mem, virtual, "image data");
> +	prev_chunk = virtual->prev_chunk;
> +
> +	qxl->bo_funcs->bo_unmap(bo);
> +	qxl->bo_funcs->bo_decref (qxl, bo);
> +	if (prev_chunk) {
> +	    bo = qxl_ums_lookup_phy_addr(qxl, prev_chunk);
> +	    assert(bo);
> +	    qxl->bo_funcs->bo_decref (qxl, bo);
> +	}
>      }
> -    
> -    qxl_free (qxl->mem, image, "image struct");
> +    qxl->bo_funcs->bo_unmap(image_bo);
> +    qxl->bo_funcs->bo_decref (qxl, image_bo);
>  }
>  
>  void
> diff --git a/src/qxl_mem.c b/src/qxl_mem.c
> index 0f80581..a2d4132 100644
> --- a/src/qxl_mem.c
> +++ b/src/qxl_mem.c
> @@ -32,10 +32,19 @@
>  #include "qxl.h"
>  #include "mspace.h"
>  
> +#include "qxl_surface.h"
>  #ifdef DEBUG_QXL_MEM
>  #include <valgrind/memcheck.h>
>  #endif
>  
> +#define QXL_BO_DATA 1
> +#define QXL_BO_SURF 2
> +#define QXL_BO_CMD 4
> +#define QXL_BO_SURF_PRIMARY 8
> +
> +#define QXL_BO_FLAG_FAIL 1
> +
> +
>  struct qxl_mem
>  {
>      mspace	space;
> @@ -124,7 +133,7 @@ qxl_mem_dump_stats   (struct qxl_mem         *mem,
>      mspace_malloc_stats (mem->space);
>  }
>  
> -void *
> +static void *
>  qxl_alloc            (struct qxl_mem         *mem,
>  		      unsigned long           n_bytes,
>  		      const char             *name)
> @@ -140,7 +149,7 @@ qxl_alloc            (struct qxl_mem         *mem,
>      return addr;
>  }
>  
> -void
> +static void
>  qxl_free             (struct qxl_mem         *mem,
>  		      void                   *d,
>  		      const char *            name)
> @@ -174,7 +183,6 @@ qxl_mem_free_all     (struct qxl_mem         *mem)
>      mem->space = create_mspace_with_base (mem->base, mem->n_bytes, 0, NULL);
>  }
>  
> -
>  static uint8_t
>  setup_slot (qxl_screen_t *qxl, uint8_t slot_index_offset,
>              unsigned long start_phys_addr, unsigned long end_phys_addr,
> @@ -265,13 +273,15 @@ qxl_garbage_collect_internal (qxl_screen_t *qxl, uint64_t id)
>       */
>  #define POINTER_MASK ((1 << 2) - 1)
>  
> -    union QXLReleaseInfo *info = u64_to_pointer (id & ~POINTER_MASK);
> +    struct qxl_bo *info_bo = (struct qxl_bo *)(id & ~POINTER_MASK);
> +    union QXLReleaseInfo *info = qxl->bo_funcs->bo_map(info_bo);
>      struct QXLCursorCmd *cmd = (struct QXLCursorCmd *)info;
>      struct QXLDrawable *drawable = (struct QXLDrawable *)info;
>      struct QXLSurfaceCmd *surface_cmd = (struct QXLSurfaceCmd *)info;
>      int is_cursor = FALSE;
>      int is_surface = FALSE;
>      int is_drawable = FALSE;
> +    struct qxl_bo *to_free;
>  
>      if ((id & POINTER_MASK) == 1)
>  	is_cursor = TRUE;
> @@ -282,43 +292,42 @@ qxl_garbage_collect_internal (qxl_screen_t *qxl, uint64_t id)
>  
>      if (is_cursor && cmd->type == QXL_CURSOR_SET)
>      {
> -	struct QXLCursor *cursor = (void *)virtual_address (
> -	    qxl, u64_to_pointer (cmd->u.set.shape), qxl->main_mem_slot);
> -
> -	qxl_free (qxl->mem, cursor, "cursor image");
> +	to_free = qxl_ums_lookup_phy_addr(qxl, cmd->u.set.shape);
> +	qxl->bo_funcs->bo_decref (qxl, to_free);
>      }
>      else if (is_drawable && drawable->type == QXL_DRAW_COPY)
>      {
> -	struct QXLImage *image = virtual_address (
> -	    qxl, u64_to_pointer (drawable->u.copy.src_bitmap), qxl->main_mem_slot);
> +	struct QXLImage *image;
> +
> +	to_free = qxl_ums_lookup_phy_addr(qxl, drawable->u.copy.src_bitmap);
> +	image = qxl->bo_funcs->bo_map(to_free);
>  
>  	if (image->descriptor.type == SPICE_IMAGE_TYPE_SURFACE)
>  	{
>  	    qxl_surface_unref (qxl->surface_cache, image->surface_image.surface_id);
>  	    qxl_surface_cache_sanity_check (qxl->surface_cache);
> -	    qxl_free (qxl->mem, image, "surface image");
> +	    qxl->bo_funcs->bo_unmap(to_free);
> +	    qxl->bo_funcs->bo_decref (qxl, to_free);
>  	}
>  	else
>  	{
> -	    qxl_image_destroy (qxl, image);
> +	    qxl->bo_funcs->bo_unmap(to_free);
> +	    qxl_image_destroy (qxl, to_free);
>  	}
>      }
>      else if (is_drawable && drawable->type == QXL_DRAW_COMPOSITE)
>      {
> -	struct QXLTransform *src_trans, *mask_trans;
> -	struct QXLImage *src_img, *mask_img;
> +	struct qxl_bo *bo;
>  	struct QXLComposite *composite = &drawable->u.composite;
>  
>  	/* Source */
> -	src_img = virtual_address (
> -	    qxl, u64_to_pointer (drawable->u.composite.src), qxl->main_mem_slot);
> -	qxl_free (qxl->mem, src_img, "image struct");
> +	bo = qxl_ums_lookup_phy_addr(qxl, drawable->u.composite.src);
> +	qxl->bo_funcs->bo_decref (qxl, bo);
>  
>  	if (composite->src_transform)
>  	{
> -	    src_trans = virtual_address (
> -		qxl, u64_to_pointer (composite->src_transform), qxl->main_mem_slot);
> -	    qxl_free (qxl->mem, src_trans, "transform");
> +	    bo = qxl_ums_lookup_phy_addr(qxl, composite->src_transform);
> +	    qxl->bo_funcs->bo_decref (qxl, bo);
>  	}
>  
>  	/* Mask */
> @@ -326,15 +335,11 @@ qxl_garbage_collect_internal (qxl_screen_t *qxl, uint64_t id)
>  	{
>  	    if (drawable->u.composite.mask_transform)
>  	    {
> -		mask_trans = virtual_address (
> -		    qxl, u64_to_pointer (drawable->u.composite.mask_transform), qxl->main_mem_slot);
> -
> -		qxl_free (qxl->mem, mask_trans, "transform");
> +		bo = qxl_ums_lookup_phy_addr(qxl, drawable->u.composite.mask_transform);
> +		qxl->bo_funcs->bo_decref (qxl, bo);
>  	    }
> -
> -	    mask_img = virtual_address (
> -		qxl, u64_to_pointer (drawable->u.composite.mask), qxl->main_mem_slot);
> -	    qxl_free (qxl->mem, mask_img, "image struct");
> +	    bo = qxl_ums_lookup_phy_addr(qxl, drawable->u.composite.mask);
> +	    qxl->bo_funcs->bo_decref (qxl, bo);
>  	}
>      }
>      else if (is_surface && surface_cmd->type == QXL_SURFACE_CMD_DESTROY)
> @@ -345,7 +350,8 @@ qxl_garbage_collect_internal (qxl_screen_t *qxl, uint64_t id)
>  
>      id = info->next;
>  
> -    qxl_free (qxl->mem, info, "command");
> +    qxl->bo_funcs->bo_unmap(info_bo);
> +    qxl->bo_funcs->bo_decref(qxl, info_bo);
>  
>      return id;
>  }
> @@ -433,3 +439,282 @@ qxl_allocnf (qxl_screen_t *qxl, unsigned long size, const char *name)
>  
>      return result;
>  }
> +
> +struct qxl_ums_bo {
> +    void *virt_addr;
> +    const char *name;
> +    int type;
> +    uint32_t size;
> +    void *internal_virt_addr;
> +    int refcnt;
> +    qxl_screen_t *qxl;
> +    struct xorg_list bos;
> +};
> +
> +static struct qxl_bo *qxl_bo_alloc_internal(qxl_screen_t *qxl, int type, int flags, unsigned long size, const char *name)
> +{
> +    struct qxl_ums_bo *bo;
> +    struct qxl_mem *mptr;
> +
> +    bo = calloc(1, sizeof(struct qxl_ums_bo));
> +    if (!bo)
> +	return NULL;
> +
> +    bo->size = size;
> +    bo->name = name;
> +    bo->type = type;
> +    bo->qxl = qxl;
> +    bo->refcnt = 1;
> +    if (type == QXL_BO_SURF)
> +	mptr = qxl->surf_mem;
> +    else
> +	mptr = qxl->mem;
> +
> +    if (flags & QXL_BO_FLAG_FAIL) {
> +	bo->internal_virt_addr = qxl_alloc(mptr, size, name);
> +	if (!bo->internal_virt_addr) {
> +	    free(bo);
> +	    return NULL;
> +	}
> +    } else
> +	bo->internal_virt_addr = qxl_allocnf(qxl, size, name);
> +
> +    if (type != QXL_BO_SURF) {
> +	xorg_list_add(&bo->bos, &qxl->ums_bos);
> +    }
> +    return (struct qxl_bo *)bo;
> +}
> +
> +static struct qxl_bo *qxl_bo_alloc(qxl_screen_t *qxl, unsigned long size, const char *name)
> +{
> +    return qxl_bo_alloc_internal(qxl, QXL_BO_DATA, 0, size, name);
> +}
> +
> +static struct qxl_bo *qxl_cmd_alloc(qxl_screen_t *qxl, unsigned long size, const char *name)
> +{
> +    return qxl_bo_alloc_internal(qxl, QXL_BO_CMD, 0, size, name);
> +}
> +
> +static void *qxl_bo_map(struct qxl_bo *_bo)
> +{
> +    struct qxl_ums_bo *bo = (struct qxl_ums_bo *)_bo;
> +    if (bo->virt_addr)
> +	ErrorF("recursive map %p\n", bo);
> +    bo->virt_addr = bo->internal_virt_addr;
> +    return bo->virt_addr;
> +}
> +
> +static void qxl_bo_unmap(struct qxl_bo *_bo)
> +{
> +    struct qxl_ums_bo *bo = (struct qxl_ums_bo *)_bo;
> +    if (!bo->virt_addr)
> +	ErrorF("unbalanced unmap %p\n", bo);
> +    bo->virt_addr = NULL;
> +}
> +
> +static void qxl_bo_output_bo_reloc(qxl_screen_t *qxl, uint32_t dst_offset,
> +				struct qxl_bo *_dst_bo,
> +				struct qxl_bo *_src_bo)
> +{
> +    struct qxl_ums_bo *src_bo = (struct qxl_ums_bo *)_src_bo;
> +    struct qxl_ums_bo *dst_bo = (struct qxl_ums_bo *)_dst_bo;
> +    uint8_t slot_id;
> +    uint64_t value;
> +
> +    /* take a refernce on the bo */
> +    src_bo->refcnt++;
> +
> +    slot_id = src_bo->type == QXL_BO_SURF ? qxl->vram_mem_slot : qxl->main_mem_slot;
> +    value = physical_address(qxl, src_bo->internal_virt_addr, slot_id);
> +
> +    *(uint64_t *)((char *)dst_bo->internal_virt_addr + dst_offset) = value;
> +}
> +
> +static void qxl_bo_output_cmd_reloc(qxl_screen_t *qxl, QXLCommand *command,
> +				    struct qxl_bo *_src_bo)
> +{
> +    struct qxl_ums_bo *src_bo = (struct qxl_ums_bo *)_src_bo;
> +    uint64_t value;
> +    uint8_t slot_id;
> +
> +    src_bo->refcnt++;
> +
> +    slot_id = src_bo->type == QXL_BO_SURF ? qxl->vram_mem_slot : qxl->main_mem_slot;
> +    value = physical_address(qxl, src_bo->internal_virt_addr, slot_id);
> +
> +    command->data = value;
> +}
> +
> +struct qxl_bo *qxl_ums_lookup_phy_addr(qxl_screen_t *qxl, uint64_t phy_addr)
> +{
> +    struct qxl_ums_bo *bo, *found = NULL;
> +    uint8_t slot_id;
> +    void *virt_addr;
> +
> +    slot_id = qxl->main_mem_slot;
> +    virt_addr = (void *)virtual_address(qxl, u64_to_pointer(phy_addr), slot_id);
> +    
> +    xorg_list_for_each_entry(bo, &qxl->ums_bos, bos) {
> +	if (bo->internal_virt_addr == virt_addr && bo->type == QXL_BO_DATA) {
> +	    found = bo;
> +	    break;
> +	}
> +    }
> +    return (struct qxl_bo *)found;
> +}
> +
> +static void qxl_bo_incref(qxl_screen_t *qxl, struct qxl_bo *_bo)
> +{
> +    struct qxl_ums_bo *bo = (struct qxl_ums_bo *)_bo;
> +    bo->refcnt++;
> +}
> +
> +static void qxl_bo_decref(qxl_screen_t *qxl, struct qxl_bo *_bo)
> +{
> +    struct qxl_ums_bo *bo = (struct qxl_ums_bo *)_bo;
> +    struct qxl_mem *mptr;
> +
> +    bo->refcnt--;
> +
> +    if (bo->refcnt > 0)
> +	return;
> +
> +    if (bo->type == QXL_BO_SURF_PRIMARY)
> +        goto out_free;
> +
> +    if (bo->type == QXL_BO_SURF)
> +	mptr = qxl->surf_mem;
> +    else
> +	mptr = qxl->mem;
> +
> +    qxl_free(mptr, bo->internal_virt_addr, bo->name);
> +    if (bo->type != QXL_BO_SURF)
> +	xorg_list_del(&bo->bos);
> +out_free:
> +    free(bo);
> +}
> +
> +static void qxl_bo_write_command(qxl_screen_t *qxl, uint32_t cmd_type, struct qxl_bo *bo)
> +{
> +    struct QXLCommand cmd;
> +
> +    /* When someone runs "init 3", the device will be 
> +     * switched into VGA mode and there is nothing we
> +     * can do about it. We get no notification.
> +     * 
> +     * However, if commands are submitted when the device
> +     * is in VGA mode, they will be queued up, and then
> +     * the next time a mode set set, an assertion in the
> +     * device will take down the entire virtual machine.
> +     *
> +     * For surface commands this is not relevant, we send
> +     * them regardless.
> +     */
> +
> +    if (!qxl->pScrn->vtSema && cmd_type != QXL_CMD_SURFACE)
> +	return;
> +
> +    cmd.type = cmd_type;
> +    qxl_bo_output_cmd_reloc(qxl, &cmd, bo);
> +
> +    if (cmd_type == QXL_CMD_CURSOR)
> +	qxl_ring_push (qxl->cursor_ring, &cmd);
> +    else
> +	qxl_ring_push (qxl->command_ring, &cmd);
> +
> +    qxl_bo_decref(qxl, bo);
> +}
> +
> +static void qxl_bo_update_area(qxl_surface_t *surf, int x1, int y1, int x2, int y2)
> +{
> +    struct QXLRam *ram_header = get_ram_header(surf->qxl);
> +    
> +    ram_header->update_area.top = y1;
> +    ram_header->update_area.bottom = y2;
> +    ram_header->update_area.left = x1;
> +    ram_header->update_area.right = x2;
> +
> +    ram_header->update_surface = surf->id;
> +
> +    qxl_update_area(surf->qxl);
> +}
> +
> +/* create a fake bo for the primary */
> +static struct qxl_bo *qxl_bo_create_primary(qxl_screen_t *qxl, uint32_t width, uint32_t height, int32_t stride, uint32_t format)
> +{
> +    struct qxl_ums_bo *bo;
> +    struct QXLRam *ram_header =
> +	(void *)((unsigned long)qxl->ram + qxl->rom->ram_header_offset);
> +
> +    struct QXLSurfaceCreate *create = &(ram_header->create_surface);
> +
> +    create->width = width;
> +    create->height = height;
> +    create->stride = - stride;
> +    create->format = format;
> +    create->position = 0; /* What is this? The Windows driver doesn't use it */
> +    create->flags = 0;
> +    create->type = QXL_SURF_TYPE_PRIMARY;
> +    create->mem = physical_address (qxl, qxl->ram, qxl->main_mem_slot);
> +
> +    qxl_io_create_primary(qxl);
> +
> +    bo = calloc(1, sizeof(struct qxl_ums_bo));
> +    if (!bo)
> +        return NULL;
> +
> +    bo->size = stride * height;
> +    bo->name = "primary";
> +    bo->type = QXL_BO_SURF_PRIMARY;
> +    bo->qxl = qxl;
> +    bo->refcnt = 1;
> +    bo->internal_virt_addr = (uint8_t *)qxl->ram + stride * (height - 1);
> +
> +    qxl->primary_bo = (struct qxl_bo *)bo;
> +    return (struct qxl_bo *)bo;
> +}
> +
> +static void qxl_bo_destroy_primary(qxl_screen_t *qxl, struct qxl_bo *bo)
> +{
> +    free(bo);
> +    qxl->primary_bo = NULL;
> +
> +    qxl_io_destroy_primary (qxl);
> +}
> +
> +static void qxl_bo_output_surf_reloc(qxl_screen_t *qxl, uint32_t dst_offset,
> +				     struct qxl_bo *_dst_bo, qxl_surface_t *surf)
> +{
> +    struct qxl_ums_bo *dst_bo = (struct qxl_ums_bo *)_dst_bo;
> +
> +    *(uint32_t *)((char *)dst_bo->internal_virt_addr + dst_offset) = surf->id;
> +}
> +
> +struct qxl_bo_funcs qxl_ums_bo_funcs = {
> +    qxl_bo_alloc,
> +    qxl_cmd_alloc,
> +    qxl_bo_map,
> +    qxl_bo_unmap,
> +    qxl_bo_decref,
> +    qxl_bo_incref,
> +    qxl_bo_output_bo_reloc,
> +    qxl_bo_write_command,
> +    qxl_bo_update_area,
> +    qxl_bo_create_primary,
> +    qxl_bo_destroy_primary,
> +    qxl_surface_create,
> +    qxl_surface_kill,
> +    qxl_bo_output_surf_reloc,
> +};
> +
> +void qxl_ums_setup_funcs(qxl_screen_t *qxl)
> +{
> +    qxl->bo_funcs = &qxl_ums_bo_funcs;
> +}
> +
> +struct qxl_bo *qxl_ums_surf_mem_alloc(qxl_screen_t *qxl, uint32_t size)
> +{
> +    struct qxl_bo *bo;
> +    bo = qxl_bo_alloc_internal (qxl, QXL_BO_SURF, QXL_BO_FLAG_FAIL, size, "surface memory");
> +    return bo;
> +}
> diff --git a/src/qxl_surface.c b/src/qxl_surface.c
> index eaf1761..e175697 100644
> --- a/src/qxl_surface.c
> +++ b/src/qxl_surface.c
> @@ -303,8 +303,9 @@ qxl_surface_recycle (surface_cache_t *cache, uint32_t id)
>      qxl_surface_t *surface = cache->all_surfaces + id;
>  
>      n_live--;
> -    qxl_free (cache->qxl->surf_mem, surface->address, "surface memory");
> -
> +    if (surface->bo)
> +	cache->qxl->bo_funcs->bo_decref (cache->qxl, surface->bo);
> +    surface->bo = NULL;
>      surface->next = cache->free_surfaces;
>      cache->free_surfaces = surface;
>  }
> @@ -319,14 +320,12 @@ qxl_surface_t *
>  qxl_surface_cache_create_primary (qxl_screen_t *qxl,
>  				  struct QXLMode	*mode)
>  {
> -    struct QXLRam *ram_header =
> -	(void *)((unsigned long)qxl->ram + qxl->rom->ram_header_offset);
> -    struct QXLSurfaceCreate *create = &(ram_header->create_surface);
>      pixman_format_code_t format;
>      uint8_t *dev_addr;
>      pixman_image_t *dev_image, *host_image;
>      qxl_surface_t *surface;
> -    surface_cache_t *cache = qxl->surface_cache;
> +    surface_cache_t	*cache = qxl->surface_cache;
> +    struct qxl_bo *bo;
>  
>      if (mode->bits == 16)
>      {
> @@ -338,24 +337,14 @@ qxl_surface_cache_create_primary (qxl_screen_t *qxl,
>      }
>      else
>      {
> -	xf86DrvMsg (cache->qxl->pScrn->scrnIndex, X_ERROR,
> +	xf86DrvMsg (qxl->pScrn->scrnIndex, X_ERROR,
>  		    "Unknown bit depth %d\n", mode->bits);
>  	return NULL;
>      }
> -	
> -    create->width = mode->x_res;
> -    create->height = mode->y_res;
> -    create->stride = - mode->stride;
> -    create->format = mode->bits;
> -    create->position = 0; /* What is this? The Windows driver doesn't use it */
> -    create->flags = 0;
> -    create->type = QXL_SURF_TYPE_PRIMARY;
> -    create->mem = physical_address (cache->qxl, cache->qxl->ram, cache->qxl->main_mem_slot);
>  
> -    qxl_io_create_primary(qxl);
> -
> -    dev_addr = (uint8_t *)qxl->ram + mode->stride * (mode->y_res - 1);
> +    bo = qxl->bo_funcs->create_primary(qxl, mode->x_res, mode->y_res, mode->stride, mode->bits);
>  
> +    dev_addr = qxl->bo_funcs->bo_map(bo);
>      dev_image = pixman_image_create_bits (format, mode->x_res, mode->y_res,
>  					  (uint32_t *)dev_addr, -mode->stride);
>  
> @@ -382,6 +371,7 @@ qxl_surface_cache_create_primary (qxl_screen_t *qxl,
>      surface->next = NULL;
>      surface->prev = NULL;
>      surface->evacuated = NULL;
> +    surface->bo = bo;
>      
>      REGION_INIT (NULL, &(surface->access_region), (BoxPtr)NULL, 0);
>      surface->access_type = UXA_ACCESS_RO;
> @@ -392,35 +382,36 @@ qxl_surface_cache_create_primary (qxl_screen_t *qxl,
>  void *
>  qxl_surface_get_host_bits(qxl_surface_t *surface)
>  {
> +    if (!surface)
> +	return NULL;

Looks like a separate fix, could use a separate patch. Up to you.

>      return (void *) pixman_image_get_data(surface->host_image);
>  }
>  
> -static struct QXLSurfaceCmd *
> +static struct qxl_bo *
>  make_surface_cmd (surface_cache_t *cache, uint32_t id, QXLSurfaceCmdType type)
>  {
> +    struct qxl_bo *cmd_bo;
>      struct QXLSurfaceCmd *cmd;
>      qxl_screen_t *qxl = cache->qxl;
>  
> -    cmd = qxl_allocnf (qxl, sizeof *cmd, "surface command");
> +    cmd_bo = qxl->bo_funcs->cmd_alloc (qxl, sizeof *cmd, "surface command");
> +    cmd = qxl->bo_funcs->bo_map(cmd_bo);
>  
> -    cmd->release_info.id = pointer_to_u64 (cmd) | 2;
> +    cmd->release_info.id = pointer_to_u64 (cmd_bo) | 2;
>      cmd->type = type;
>      cmd->flags = 0;
>      cmd->surface_id = id;
>      
> -    return cmd;
> +    qxl->bo_funcs->bo_unmap(cmd_bo);
> +    return cmd_bo;
>  }
>  
>  static void
> -push_surface_cmd (surface_cache_t *cache, struct QXLSurfaceCmd *cmd)
> +push_surface_cmd (surface_cache_t *cache, struct qxl_bo *cmd_bo)
>  {
> -    struct QXLCommand command;
>      qxl_screen_t *qxl = cache->qxl;
> -
> -    command.type = QXL_CMD_SURFACE;
> -    command.data = physical_address (qxl, cmd, qxl->main_mem_slot);
>      
> -    qxl_ring_push (qxl->command_ring, &command);
> +    qxl->bo_funcs->write_command (qxl, QXL_CMD_SURFACE, cmd_bo);

I think you are actually fixing another possible bug here, because
write_command will check vtSema. But I think no reason to make a
separate patch here at all.

>  }
>  
>  enum ROPDescriptor
> @@ -438,25 +429,25 @@ enum ROPDescriptor
>      ROPD_INVERS_RES = (1 <<10),
>  };
>  
> -static struct QXLDrawable *
> +static struct qxl_bo *
>  make_drawable (qxl_screen_t *qxl, qxl_surface_t *surf, uint8_t type,
>  	       const struct QXLRect *rect
>  	       /* , pRegion clip */)
>  {
>      struct QXLDrawable *drawable;
> +    struct qxl_bo *draw_bo;
>      int i;
> -    
> -    drawable = qxl_allocnf (qxl, sizeof *drawable, "drawable command");
> +   
> +    draw_bo = qxl->bo_funcs->cmd_alloc (qxl, sizeof *drawable, "drawable command");
> +    assert(draw_bo);
> +    drawable = qxl->bo_funcs->bo_map(draw_bo);
>      assert(drawable);
>      
> -    drawable->release_info.id = pointer_to_u64 (drawable);
> +    drawable->release_info.id = pointer_to_u64 (draw_bo);
>      
>      drawable->type = type;
>      
> -    if (surf)
> -	drawable->surface_id = surf->id;		/* Only primary for now */
> -    else
> -	drawable->surface_id = 0;
> +    qxl->bo_funcs->bo_output_surf_reloc(qxl, offsetof(struct QXLDrawable, surface_id), draw_bo, surf);
>  
>      drawable->effect = QXL_EFFECT_OPAQUE;
>      drawable->self_bitmap = 0;
> @@ -480,41 +471,27 @@ make_drawable (qxl_screen_t *qxl, qxl_surface_t *surf, uint8_t type,
>  	drawable->bbox = *rect;
>      
>      drawable->mm_time = qxl->rom->mm_clock;
> -    
> -    return drawable;
> +
> +    qxl->bo_funcs->bo_unmap(draw_bo);
> +    return draw_bo;
>  }
>  
>  static void
> -push_drawable (qxl_screen_t *qxl, struct QXLDrawable *drawable)
> +push_drawable (qxl_screen_t *qxl, struct qxl_bo *drawable_bo)
>  {
> -    struct QXLCommand cmd;
> -    
> -    /* When someone runs "init 3", the device will be 
> -     * switched into VGA mode and there is nothing we
> -     * can do about it. We get no notification.
> -     * 
> -     * However, if commands are submitted when the device
> -     * is in VGA mode, they will be queued up, and then
> -     * the next time a mode set set, an assertion in the
> -     * device will take down the entire virtual machine.
> -     */
> -    if (qxl->pScrn->vtSema)
> -    {
> -	cmd.type = QXL_CMD_DRAW;
> -	cmd.data = physical_address (qxl, drawable, qxl->main_mem_slot);
> -	
> -	qxl_ring_push (qxl->command_ring, &cmd);
> -    }
> +    qxl->bo_funcs->write_command (qxl, QXL_CMD_DRAW, drawable_bo);
>  }
>  
>  static void
>  submit_fill (qxl_screen_t *qxl, qxl_surface_t *surf,
>  	     const struct QXLRect *rect, uint32_t color)
>  {
> +    struct qxl_bo *drawable_bo;
>      struct QXLDrawable *drawable;
>      
> -    drawable = make_drawable (qxl, surf, QXL_DRAW_FILL, rect);
> +    drawable_bo = make_drawable (qxl, surf, QXL_DRAW_FILL, rect);
>      
> +    drawable = qxl->bo_funcs->bo_map(drawable_bo);
>      drawable->u.fill.brush.type = SPICE_BRUSH_TYPE_SOLID;
>      drawable->u.fill.brush.u.color = color;
>      drawable->u.fill.rop_descriptor = ROPD_OP_PUT;
> @@ -523,7 +500,9 @@ submit_fill (qxl_screen_t *qxl, qxl_surface_t *surf,
>      drawable->u.fill.mask.pos.y = 0;
>      drawable->u.fill.mask.bitmap = 0;
>      
> -    push_drawable (qxl, drawable);
> +    qxl->bo_funcs->bo_unmap(drawable_bo);
> +
> +    push_drawable (qxl, drawable_bo);
>  }
>  
>  static qxl_surface_t *
> @@ -576,8 +555,8 @@ surface_send_create (surface_cache_t *cache,
>      int n_attempts = 0;
>      qxl_screen_t *qxl = cache->qxl;
>      qxl_surface_t *surface;
> -    void *address;
> -
> +    struct qxl_bo *bo, *cmd_bo;
> +    void *dev_ptr;
>      get_formats (bpp, &format, &pformat);
>      
>      width = align (width);
> @@ -591,9 +570,9 @@ surface_send_create (surface_cache_t *cache,
>       */
>      qxl_garbage_collect (qxl);
>  retry2:
> -    address = qxl_alloc (qxl->surf_mem, stride * height + stride, "surface memory");
> +    bo = qxl_ums_surf_mem_alloc(qxl, stride * height + stride);
>  
> -    if (!address)
> +    if (!bo)
>      {
>  	ErrorF ("- %dth attempt\n", n_attempts++);
>  
> @@ -623,30 +602,31 @@ retry:
>  	if (!qxl_handle_oom (cache->qxl))
>  	{
>  	    ErrorF ("  Out of surfaces\n");
> -	    qxl_free (qxl->surf_mem, address, "surface memory");
> +	    qxl->bo_funcs->bo_decref (qxl, bo);
>  	    return NULL;
>  	}
>  	else
>  	    goto retry;
>      }
>  
> -    surface->address = address;    
> -    surface->end = (char *)address + stride * height;
> +    surface->bo = bo;
>      
> -    cmd = make_surface_cmd (cache, surface->id, QXL_SURFACE_CMD_CREATE);
> +    cmd_bo = make_surface_cmd (cache, surface->id, QXL_SURFACE_CMD_CREATE);
>  
> +    cmd = qxl->bo_funcs->bo_map(cmd_bo);
>      cmd->u.surface_create.format = format;
>      cmd->u.surface_create.width = width;
>      cmd->u.surface_create.height = height;
>      cmd->u.surface_create.stride = - stride;
> +    qxl->bo_funcs->bo_unmap(cmd_bo);
>  
> -    cmd->u.surface_create.data =
> -      physical_address (qxl, surface->address, qxl->vram_mem_slot);
> +    qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(struct QXLSurfaceCmd, u.surface_create.data), cmd_bo, surface->bo);
>  
> -    push_surface_cmd (cache, cmd);
> +    push_surface_cmd (cache, cmd_bo);
>  
> +    dev_ptr = qxl->bo_funcs->bo_map(surface->bo);
>      dev_addr
> -	= (uint32_t *)((uint8_t *)surface->address + stride * (height - 1));
> +	= (uint32_t *)((uint8_t *)dev_ptr + stride * (height - 1));
>  
>      surface->dev_image = pixman_image_create_bits (
>  	pformat, width, height, dev_addr, - stride);
> @@ -654,6 +634,7 @@ retry:
>      surface->host_image = pixman_image_create_bits (
>  	pformat, width, height, NULL, -1);
>  
> +    qxl->bo_funcs->bo_unmap(surface->bo);
>      surface->bpp = bpp;
>  
>      n_live++;
> @@ -751,7 +732,7 @@ unlink_surface (qxl_surface_t *surface)
>  static void
>  surface_destroy (qxl_surface_t *surface)
>  {
> -    struct QXLSurfaceCmd *cmd;
> +    struct qxl_bo *cmd_bo;
>  
>      if (surface->dev_image)
>  	pixman_image_unref (surface->dev_image);
> @@ -761,9 +742,11 @@ surface_destroy (qxl_surface_t *surface)
>  #if 0
>      ErrorF("destroy %ld\n", (long int)surface->end - (long int)surface->address);
>  #endif
> -    cmd = make_surface_cmd (surface->cache, surface->id, QXL_SURFACE_CMD_DESTROY);
> +    cmd_bo = make_surface_cmd (surface->cache, surface->id, QXL_SURFACE_CMD_DESTROY);
> +
> +    push_surface_cmd (surface->cache, cmd_bo);
>  
> -    push_surface_cmd (surface->cache, cmd);
> +    surface->cache->qxl->bo_funcs->bo_decref(surface->cache->qxl, surface->bo);
>  }
>  
>  static void
> @@ -907,16 +890,7 @@ download_box_no_update (qxl_surface_t *surface, int x1, int y1, int x2, int y2)
>  static void
>  download_box (qxl_surface_t *surface, int x1, int y1, int x2, int y2)
>  {
> -    struct QXLRam *ram_header = get_ram_header (surface->cache->qxl);
> -    
> -    ram_header->update_area.top = y1;
> -    ram_header->update_area.bottom = y2;
> -    ram_header->update_area.left = x1;
> -    ram_header->update_area.right = x2;
> -    
> -    ram_header->update_surface = surface->id;
> -
> -    qxl_update_area(surface->cache->qxl);
> +    surface->qxl->bo_funcs->update_area(surface, x1, y1, x2, y2);
>  
>      download_box_no_update(surface, x1, y1, x2, y2);
>  }
> @@ -995,7 +969,7 @@ real_upload_box (qxl_surface_t *surface, int x1, int y1, int x2, int y2)
>  {
>      struct QXLRect rect;
>      struct QXLDrawable *drawable;
> -    struct QXLImage *image;
> +    struct qxl_bo *image_bo, *drawable_bo;
>      qxl_screen_t *qxl = surface->qxl;
>      uint32_t *data;
>      int stride;
> @@ -1005,7 +979,8 @@ real_upload_box (qxl_surface_t *surface, int x1, int y1, int x2, int y2)
>      rect.top = y1;
>      rect.bottom = y2;
>      
> -    drawable = make_drawable (qxl, surface, QXL_DRAW_COPY, &rect);
> +    drawable_bo = make_drawable (qxl, surface, QXL_DRAW_COPY, &rect);
> +    drawable = qxl->bo_funcs->bo_map(drawable_bo);
>      drawable->u.copy.src_area = rect;
>      translate_rect (&drawable->u.copy.src_area);
>      drawable->u.copy.rop_descriptor = ROPD_OP_PUT;
> @@ -1015,16 +990,19 @@ real_upload_box (qxl_surface_t *surface, int x1, int y1, int x2, int y2)
>      drawable->u.copy.mask.pos.y = 0;
>      drawable->u.copy.mask.bitmap = 0;
>  
> +    qxl->bo_funcs->bo_unmap(drawable_bo);
> +
>      data = pixman_image_get_data (surface->host_image);
>      stride = pixman_image_get_stride (surface->host_image);
>      
> -    image = qxl_image_create (
> +    image_bo = qxl_image_create (
>  	qxl, (const uint8_t *)data, x1, y1, x2 - x1, y2 - y1, stride, 
>  	surface->bpp == 24 ? 4 : surface->bpp / 8, TRUE);
> -    drawable->u.copy.src_bitmap =
> -	physical_address (qxl, image, qxl->main_mem_slot);
> -    
> -    push_drawable (qxl, drawable);
> +    qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.copy.src_bitmap),
> +				   drawable_bo, image_bo);
> +    push_drawable (qxl, drawable_bo);
> +
> +    qxl->bo_funcs->bo_decref(qxl, image_bo);
>  }
>  
>  #define TILE_WIDTH 512
> @@ -1056,8 +1034,8 @@ static void
>  upload_one_primary_region(qxl_screen_t *qxl, PixmapPtr pixmap, BoxPtr b)
>  {
>      struct QXLRect rect;
> +    struct qxl_bo *drawable_bo, *image_bo;
>      struct QXLDrawable *drawable;
> -    struct QXLImage *image;
>      FbBits *data;
>      int stride;
>      int bpp;
> @@ -1067,7 +1045,8 @@ upload_one_primary_region(qxl_screen_t *qxl, PixmapPtr pixmap, BoxPtr b)
>      rect.top = b->y1;
>      rect.bottom = b->y2;
>  
> -    drawable = make_drawable (qxl, NULL, QXL_DRAW_COPY, &rect);
> +    drawable_bo = make_drawable (qxl, NULL, QXL_DRAW_COPY, &rect);
> +    drawable = qxl->bo_funcs->bo_map(drawable_bo);
>      drawable->u.copy.src_area = rect;
>      translate_rect (&drawable->u.copy.src_area);
>      drawable->u.copy.rop_descriptor = ROPD_OP_PUT;
> @@ -1076,15 +1055,17 @@ upload_one_primary_region(qxl_screen_t *qxl, PixmapPtr pixmap, BoxPtr b)
>      drawable->u.copy.mask.pos.x = 0;
>      drawable->u.copy.mask.pos.y = 0;
>      drawable->u.copy.mask.bitmap = 0;
> +    qxl->bo_funcs->bo_unmap(drawable_bo);
>  
>      fbGetPixmapBitsData(pixmap, data, stride, bpp);
> -    image = qxl_image_create (
> +    image_bo = qxl_image_create (
>  	qxl, (const uint8_t *)data, b->x1, b->y1, b->x2 - b->x1, b->y2 - b->y1, stride * sizeof(*data),
>  	bpp == 24 ? 4 : bpp / 8, TRUE);
> -    drawable->u.copy.src_bitmap =
> -	physical_address (qxl, image, qxl->main_mem_slot);
> +    qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.copy.src_bitmap),
> +				   drawable_bo, image_bo);
>  
> -    push_drawable (qxl, drawable);
> +    push_drawable (qxl, drawable_bo);
> +    qxl->bo_funcs->bo_decref(qxl, image_bo);
>  }
>  
>  void
> @@ -1326,6 +1307,7 @@ qxl_surface_copy (qxl_surface_t *dest,
>  		  int width, int height)
>  {
>      qxl_screen_t *qxl = dest->qxl;
> +    struct qxl_bo *drawable_bo;
>      struct QXLDrawable *drawable;
>      struct QXLRect qrect;
>  
> @@ -1341,26 +1323,36 @@ qxl_surface_copy (qxl_surface_t *dest,
>      
>      if (dest->id == dest->u.copy_src->id)
>      {
> -	drawable = make_drawable (qxl, dest, QXL_COPY_BITS, &qrect);
> +	drawable_bo = make_drawable (qxl, dest, QXL_COPY_BITS, &qrect);
>  
> +	drawable = qxl->bo_funcs->bo_map(drawable_bo);
>  	drawable->u.copy_bits.src_pos.x = src_x1;
>  	drawable->u.copy_bits.src_pos.y = src_y1;
> +	qxl->bo_funcs->bo_unmap(drawable_bo);
> +
> +	push_drawable (qxl, drawable_bo);
> +
>      }
>      else
>      {
> -	struct QXLImage *image = qxl_allocnf (qxl, sizeof *image, "surface image struct");
> +	struct qxl_bo *image_bo;
> +	struct QXLImage *image;
>  
>  	dest->u.copy_src->ref_count++;
> -
> +	image_bo = qxl->bo_funcs->bo_alloc (qxl, sizeof(struct QXLImage), "image struct for surface");
> +	image = qxl->bo_funcs->bo_map(image_bo);
>  	image->descriptor.id = 0;
>  	image->descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
>  	image->descriptor.width = 0;
>  	image->descriptor.height = 0;
>  	image->surface_image.surface_id = dest->u.copy_src->id;
> +	qxl->bo_funcs->bo_unmap(image_bo);
>  
> -	drawable = make_drawable (qxl, dest, QXL_DRAW_COPY, &qrect);
> +	drawable_bo = make_drawable (qxl, dest, QXL_DRAW_COPY, &qrect);
>  
> -	drawable->u.copy.src_bitmap = physical_address (qxl, image, qxl->main_mem_slot);
> +	drawable = qxl->bo_funcs->bo_map(drawable_bo);
> +	qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.copy.src_bitmap),
> +				       drawable_bo, image_bo);
>  	drawable->u.copy.src_area.left = src_x1;
>  	drawable->u.copy.src_area.top = src_y1;
>  	drawable->u.copy.src_area.right = src_x1 + width;
> @@ -1372,7 +1364,7 @@ qxl_surface_copy (qxl_surface_t *dest,
>  	drawable->u.copy.mask.pos.y = 0;
>  	drawable->u.copy.mask.bitmap = 0;
>  
> -	drawable->surfaces_dest[0] = dest->u.copy_src->id;
> +	qxl->bo_funcs->bo_output_surf_reloc(qxl, offsetof(struct QXLDrawable, surfaces_dest[0]), drawable_bo, dest->u.copy_src);
>  	drawable->surfaces_rects[0] = drawable->u.copy.src_area;
>   	
>  	assert (src_x1 >= 0);
> @@ -1386,9 +1378,13 @@ qxl_surface_copy (qxl_surface_t *dest,
>  	
>  	assert (width <= pixman_image_get_width (dest->u.copy_src->host_image));
>  	assert (height <= pixman_image_get_height (dest->u.copy_src->host_image));
> +
> +	qxl->bo_funcs->bo_unmap(drawable_bo);
> +	push_drawable (qxl, drawable_bo);
> +	qxl->bo_funcs->bo_decref(qxl, image_bo);
>      }
>  
> -    push_drawable (qxl, drawable);
> +

stray whitespace.

>  }
>  
>  /* composite */
> @@ -1412,13 +1408,14 @@ qxl_surface_prepare_composite (int op,
>      return TRUE;
>  }
>  
> -static QXLImage *
> +static struct qxl_bo *
>  image_from_picture (qxl_screen_t *qxl,
>  		    PicturePtr picture,
>  		    qxl_surface_t *surface,
>  		    int *force_opaque)
>  {
> -    struct QXLImage *image = qxl_allocnf (qxl, sizeof *image, "image struct for picture");
> +    struct qxl_bo *image_bo = qxl->bo_funcs->bo_alloc (qxl, sizeof(struct QXLImage), "image struct for surface");
> +    struct QXLImage *image = qxl->bo_funcs->bo_map(image_bo);
>  
>      image->descriptor.id = 0;
>      image->descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
> @@ -1426,20 +1423,22 @@ image_from_picture (qxl_screen_t *qxl,
>      image->descriptor.height = 0;
>      image->surface_image.surface_id = surface->id;
>  
> +    qxl->bo_funcs->bo_unmap(image_bo);
>      if (picture->format == PICT_x8r8g8b8)
>  	*force_opaque = TRUE;
>      else
>  	*force_opaque = FALSE;
>      
> -    return image;
> +    return image_bo;
>  }
>  
> -static QXLTransform *
> +static struct qxl_bo *
>  get_transform (qxl_screen_t *qxl, PictTransform *transform)
>  {
>      if (transform)
>      {
> -	QXLTransform *qxform = qxl_allocnf (qxl, sizeof (QXLTransform), "transform");
> +	struct qxl_bo *qxform_bo = qxl->bo_funcs->bo_alloc (qxl, sizeof (QXLTransform), "transform");
> +	QXLTransform *qxform = qxl->bo_funcs->bo_map(qxform_bo);
>  
>  	qxform->t00 = transform->matrix[0][0];
>  	qxform->t01 = transform->matrix[0][1];
> @@ -1448,7 +1447,8 @@ get_transform (qxl_screen_t *qxl, PictTransform *transform)
>  	qxform->t11 = transform->matrix[1][1];
>  	qxform->t12 = transform->matrix[1][2];
>  
> -	return qxform;
> +	qxl->bo_funcs->bo_unmap(qxform_bo);
> +	return qxform_bo;
>      }
>      else
>      {
> @@ -1484,13 +1484,14 @@ qxl_surface_composite (qxl_surface_t *dest,
>      qxl_surface_t *qmask = dest->u.composite.mask;
>      int op = dest->u.composite.op;
>      struct QXLDrawable *drawable;
> +    struct qxl_bo *drawable_bo;
>      QXLComposite *composite;
>      QXLRect rect;
> -    QXLImage *img;
> -    QXLTransform *trans;
> +    struct qxl_bo *trans_bo, *img_bo;
>      int n_deps = 0;
>      int force_opaque;
> -
> +    struct qxl_bo *derefs[4];
> +    int n_derefs = 0, i;
>  #if 0
>      ErrorF ("QXL Composite: src:       %x (%d %d) id: %d; \n"
>  	    "               mask:      id: %d\n"
> @@ -1511,7 +1512,9 @@ qxl_surface_composite (qxl_surface_t *dest,
>      rect.top = dest_y;
>      rect.bottom = dest_y + height;
>      
> -    drawable = make_drawable (qxl, dest, QXL_DRAW_COMPOSITE, &rect);
> +    drawable_bo = make_drawable (qxl, dest, QXL_DRAW_COMPOSITE, &rect);
> +
> +    drawable = qxl->bo_funcs->bo_map(drawable_bo);
>  
>      composite = &drawable->u.composite;
>  
> @@ -1522,38 +1525,53 @@ qxl_surface_composite (qxl_surface_t *dest,
>      
>      composite->flags |= (op & 0xff);
>  
> -    img = image_from_picture (qxl, src, qsrc, &force_opaque);
> +    img_bo = image_from_picture (qxl, src, qsrc, &force_opaque);
>      if (force_opaque)
>  	composite->flags |= SPICE_COMPOSITE_SOURCE_OPAQUE;
> -    composite->src = physical_address (qxl, img, qxl->main_mem_slot);
> +    qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.composite.src),
> +				   drawable_bo, img_bo);
> +    derefs[n_derefs++] = img_bo;
> +
>      composite->flags |= (src->filter << 8);
>      composite->flags |= (src->repeat << 14);
> -    trans = get_transform (qxl, src->transform);
> -    composite->src_transform = trans?
> -	physical_address (qxl, trans, qxl->main_mem_slot) : 0x00000000;
> -
> -    drawable->surfaces_dest[n_deps] = qsrc->id;
> +    trans_bo = get_transform (qxl, src->transform);
> +    if (trans_bo) {
> +	qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.composite.src_transform),
> +				       drawable_bo, trans_bo);
> +	derefs[n_derefs++] = trans_bo;
> +    } else
> +	composite->src_transform = 0;
> +
> +    qxl->bo_funcs->bo_output_surf_reloc(qxl, offsetof(struct QXLDrawable, surfaces_dest[n_deps]), drawable_bo, qsrc);
>      drawable->surfaces_rects[n_deps] = full_rect (qsrc);
>  
>      n_deps++;
>      
>      if (mask)
>      {
> -	img = image_from_picture (qxl, mask, qmask, &force_opaque);
> +	img_bo = image_from_picture (qxl, mask, qmask, &force_opaque);
>  	if (force_opaque)
>  	    composite->flags |= SPICE_COMPOSITE_MASK_OPAQUE;
> -	composite->mask = physical_address (qxl, img, qxl->main_mem_slot);
> +
> +	qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.composite.mask),
> +				       drawable_bo, img_bo);
> +	derefs[n_derefs++] = img_bo;
>  	composite->flags |= (mask->filter << 11);
>  	composite->flags |= (mask->repeat << 16);
>  	composite->flags |= (mask->componentAlpha << 18);
>  
> -	drawable->surfaces_dest[n_deps] = qmask->id;
> +	qxl->bo_funcs->bo_output_surf_reloc(qxl, offsetof(struct QXLDrawable, surfaces_dest[n_deps]), drawable_bo, qmask);
>  	drawable->surfaces_rects[n_deps] = full_rect (qmask);
>  	n_deps++;
>  	
> -	trans = get_transform (qxl, src->transform);
> -	composite->mask_transform = trans?
> -	    physical_address (qxl, trans, qxl->main_mem_slot) : 0x00000000;
> +	trans_bo = get_transform (qxl, src->transform);
> +	if (trans_bo) {
> +	    qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.composite.mask_transform),
> +					   drawable_bo, trans_bo);
> +	    derefs[n_derefs++] = trans_bo;
> +	}
> +	else
> +	  composite->mask_transform = 0;
>      }
>      else
>      {
> @@ -1561,7 +1579,7 @@ qxl_surface_composite (qxl_surface_t *dest,
>  	composite->mask_transform = 0x00000000;
>      }
>  
> -    drawable->surfaces_dest[n_deps] = dest->id;
> +    qxl->bo_funcs->bo_output_surf_reloc(qxl, offsetof(struct QXLDrawable, surfaces_dest[n_deps]), drawable_bo, dest);
>      drawable->surfaces_rects[n_deps] = full_rect (dest);
>      
>      composite->src_origin.x = src_x;
> @@ -1571,7 +1589,11 @@ qxl_surface_composite (qxl_surface_t *dest,
>  
>      drawable->effect = QXL_EFFECT_BLEND;
>      
> -    push_drawable (qxl, drawable);
> +    qxl->bo_funcs->bo_unmap(drawable_bo);
> +    push_drawable (qxl, drawable_bo);
> +
> +    for (i = 0; i < n_derefs; i++)
> +      qxl->bo_funcs->bo_decref(qxl, derefs[i]);
>  }
>  
>  Bool
> @@ -1579,18 +1601,20 @@ qxl_surface_put_image (qxl_surface_t *dest,
>  		       int x, int y, int width, int height,
>  		       const char *src, int src_pitch)
>  {
> +    struct qxl_bo *drawable_bo;
>      struct QXLDrawable *drawable;
>      qxl_screen_t *qxl = dest->qxl;
>      struct QXLRect rect;
> -    struct QXLImage *image;
> -    
> +    struct qxl_bo *image_bo;
> +
>      rect.left = x;
>      rect.right = x + width;
>      rect.top = y;
>      rect.bottom = y + height;
>  
> -    drawable = make_drawable (qxl, dest, QXL_DRAW_COPY, &rect);
> +    drawable_bo = make_drawable (qxl, dest, QXL_DRAW_COPY, &rect);
>  
> +    drawable = qxl->bo_funcs->bo_map(drawable_bo);
>      drawable->u.copy.src_area.top = 0;
>      drawable->u.copy.src_area.bottom = height;
>      drawable->u.copy.src_area.left = 0;
> @@ -1603,13 +1627,15 @@ qxl_surface_put_image (qxl_surface_t *dest,
>      drawable->u.copy.mask.pos.y = 0;
>      drawable->u.copy.mask.bitmap = 0;
>  
> -    image = qxl_image_create (
> +    image_bo = qxl_image_create (
>  	qxl, (const uint8_t *)src, 0, 0, width, height, src_pitch,
>  	dest->bpp == 24 ? 4 : dest->bpp / 8, FALSE);
> -    drawable->u.copy.src_bitmap =
> -	physical_address (qxl, image, qxl->main_mem_slot);
> -    
> -    push_drawable (qxl, drawable);
> +    qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.copy.src_bitmap),
> +				   drawable_bo, image_bo);
>  
> +    qxl->bo_funcs->bo_unmap(drawable_bo);
> +    
> +    push_drawable (qxl, drawable_bo);
> +    qxl->bo_funcs->bo_decref(qxl, image_bo);    
>      return TRUE;
>  }
> diff --git a/src/qxl_surface.h b/src/qxl_surface.h
> index 0f05d9d..89e08fd 100644
> --- a/src/qxl_surface.h
> +++ b/src/qxl_surface.h
> @@ -16,9 +16,7 @@ struct qxl_surface_t
>      uxa_access_t	access_type;
>      RegionRec		access_region;
>  
> -    void *		address;
> -    void *		end;
> -    
> +    struct qxl_bo   *bo;
>      struct qxl_surface_t *	next;
>      struct qxl_surface_t *	prev;	/* Only used in the 'live'
>  				 * chain in the surface cache
> diff --git a/src/qxl_uxa.c b/src/qxl_uxa.c
> index fd70488..d1740b2 100644
> --- a/src/qxl_uxa.c
> +++ b/src/qxl_uxa.c
> @@ -358,8 +358,10 @@ qxl_create_pixmap (ScreenPtr screen, int w, int h, int depth, unsigned usage)
>  	goto fallback;
>      }
>  
> -    surface = qxl_surface_create (qxl, w, h, depth);
> +    if (!w || !h)
> +      goto fallback;
>  
> +    surface = qxl->bo_funcs->create_surface (qxl, w, h, depth);
>      if (surface)
>      {
>  	/* ErrorF ("   Successfully created surface in video memory\n"); */
> @@ -415,7 +417,7 @@ qxl_destroy_pixmap (PixmapPtr pixmap)
>  
>  	if (surface)
>  	{
> -	    qxl_surface_kill (surface);
> +	    qxl->bo_funcs->destroy_surface(surface);
>  	    set_surface (pixmap, NULL);
>  
>  	    qxl_surface_cache_sanity_check (qxl->surface_cache);
> -- 
> 1.8.1.2
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel


More information about the Spice-devel mailing list