Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright 2010 Red Hat, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * on the rights to use, copy, modify, merge, publish, distribute, sub
      8  * license, and/or sell copies of the Software, and to permit persons to whom
      9  * the Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
     19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     21  */
     22 
     23 #ifdef HAVE_CONFIG_H
     24 #include "config.h"
     25 #endif
     26 
     27 #include "qxl.h"
     28 #include "qxl_surface.h"/* send anything pending to the other side */
     29 
     30 
     31 enum ROPDescriptor
     32 {
     33     ROPD_INVERS_SRC = (1 << 0),
     34     ROPD_INVERS_BRUSH = (1 << 1),
     35     ROPD_INVERS_DEST = (1 << 2),
     36     ROPD_OP_PUT = (1 << 3),
     37     ROPD_OP_OR = (1 << 4),
     38     ROPD_OP_AND = (1 << 5),
     39     ROPD_OP_XOR = (1 << 6),
     40     ROPD_OP_BLACKNESS = (1 << 7),
     41     ROPD_OP_WHITENESS = (1 << 8),
     42     ROPD_OP_INVERS = (1 << 9),
     43     ROPD_INVERS_RES = (1 <<10),
     44 };
     45 
     46 static struct qxl_bo *
     47 make_drawable (qxl_screen_t *qxl, qxl_surface_t *surf, uint8_t type,
     48 	       const struct QXLRect *rect
     49 	       /* , pRegion clip */)
     50 {
     51     struct QXLDrawable *drawable;
     52     struct qxl_bo *draw_bo;
     53     int i;
     54 
     55     draw_bo = qxl->bo_funcs->cmd_alloc (qxl, sizeof *drawable, "drawable command");
     56     assert(draw_bo);
     57     drawable = qxl->bo_funcs->bo_map(draw_bo);
     58     assert(drawable);
     59 
     60     drawable->release_info.id = pointer_to_u64 (draw_bo);
     61 
     62     drawable->type = type;
     63 
     64     qxl->bo_funcs->bo_output_surf_reloc(qxl, offsetof(struct QXLDrawable, surface_id), draw_bo, surf);
     65 
     66     drawable->effect = QXL_EFFECT_OPAQUE;
     67     drawable->self_bitmap = 0;
     68     drawable->self_bitmap_area.top = 0;
     69     drawable->self_bitmap_area.left = 0;
     70     drawable->self_bitmap_area.bottom = 0;
     71     drawable->self_bitmap_area.right = 0;
     72     /* FIXME: add clipping */
     73     drawable->clip.type = SPICE_CLIP_TYPE_NONE;
     74 
     75     /*
     76      * surfaces_dest[i] should apparently be filled out with the
     77      * surfaces that we depend on, and surface_rects should be
     78      * filled with the rectangles of those surfaces that we
     79      * are going to use.
     80      */
     81     for (i = 0; i < 3; ++i)
     82 	drawable->surfaces_dest[i] = -1;
     83 
     84     if (rect)
     85 	drawable->bbox = *rect;
     86 
     87     /* No longer needed since spice-server commit c541d7e29 */
     88     if (!qxl->kms_enabled)
     89         drawable->mm_time = qxl->rom->mm_clock;
     90     else
     91         drawable->mm_time = 0;
     92 
     93     qxl->bo_funcs->bo_unmap(draw_bo);
     94     return draw_bo;
     95 }
     96 
     97 static void
     98 push_drawable (qxl_screen_t *qxl, struct qxl_bo *drawable_bo)
     99 {
    100     qxl->bo_funcs->write_command (qxl, QXL_CMD_DRAW, drawable_bo);
    101 }
    102 
    103 static void
    104 submit_fill (qxl_screen_t *qxl, qxl_surface_t *surf,
    105 	     const struct QXLRect *rect, uint32_t color)
    106 {
    107     struct qxl_bo *drawable_bo;
    108     struct QXLDrawable *drawable;
    109 
    110     drawable_bo = make_drawable (qxl, surf, QXL_DRAW_FILL, rect);
    111 
    112     drawable = qxl->bo_funcs->bo_map(drawable_bo);
    113     drawable->u.fill.brush.type = SPICE_BRUSH_TYPE_SOLID;
    114     drawable->u.fill.brush.u.color = color;
    115     drawable->u.fill.rop_descriptor = ROPD_OP_PUT;
    116     drawable->u.fill.mask.flags = 0;
    117     drawable->u.fill.mask.pos.x = 0;
    118     drawable->u.fill.mask.pos.y = 0;
    119     drawable->u.fill.mask.bitmap = 0;
    120 
    121     qxl->bo_funcs->bo_unmap(drawable_bo);
    122 
    123     push_drawable (qxl, drawable_bo);
    124 }
    125 
    126 void
    127 qxl_surface_flush (qxl_surface_t *surface)
    128 {
    129     ;
    130 }
    131 
    132 /* access */
    133 static void
    134 download_box_no_update (qxl_surface_t *surface, int x1, int y1, int x2, int y2)
    135 {
    136     pixman_image_composite (PIXMAN_OP_SRC,
    137                             surface->dev_image,
    138                             NULL,
    139                             surface->host_image,
    140                             x1, y1, 0, 0, x1, y1, x2 - x1, y2 - y1);
    141 }
    142 
    143 void
    144 qxl_download_box (qxl_surface_t *surface, int x1, int y1, int x2, int y2)
    145 {
    146     assert (x2 >= x1 && y2 >= y1);
    147 
    148     if (x1 == x2 || y1 == y2)
    149         return;
    150 
    151     surface->qxl->bo_funcs->update_area(surface, x1, y1, x2, y2);
    152 
    153     download_box_no_update(surface, x1, y1, x2, y2);
    154 }
    155 
    156 Bool
    157 qxl_surface_prepare_access (qxl_surface_t  *surface,
    158 			    PixmapPtr       pixmap,
    159 			    RegionPtr       region,
    160 			    uxa_access_t    access)
    161 {
    162     int n_boxes;
    163     BoxPtr boxes;
    164     ScreenPtr pScreen = pixmap->drawable.pScreen;
    165     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
    166     RegionRec new;
    167 
    168     if (!pScrn->vtSema)
    169         return FALSE;
    170 
    171     REGION_INIT (NULL, &new, (BoxPtr)NULL, 0);
    172     REGION_SUBTRACT (NULL, &new, region, &surface->access_region);
    173 
    174     if (access == UXA_ACCESS_RW)
    175 	surface->access_type = UXA_ACCESS_RW;
    176 
    177     region = &new;
    178 
    179     n_boxes = REGION_NUM_RECTS (region);
    180     boxes = REGION_RECTS (region);
    181 
    182     if (n_boxes < 25)
    183     {
    184 	while (n_boxes--)
    185 	{
    186 	    qxl_download_box (surface, boxes->x1, boxes->y1, boxes->x2, boxes->y2);
    187 
    188 	    boxes++;
    189 	}
    190     }
    191     else
    192     {
    193 	qxl_download_box (
    194 	    surface,
    195 	    new.extents.x1, new.extents.y1, new.extents.x2, new.extents.y2);
    196     }
    197 
    198     REGION_UNION (pScreen,
    199 		  &(surface->access_region),
    200 		  &(surface->access_region),
    201 		      region);
    202 
    203     REGION_UNINIT (NULL, &new);
    204 
    205     pScreen->ModifyPixmapHeader(
    206 	pixmap,
    207 	pixmap->drawable.width,
    208 	pixmap->drawable.height,
    209 	-1, -1, -1,
    210 	pixman_image_get_data (surface->host_image));
    211 
    212     pixmap->devKind = pixman_image_get_stride (surface->host_image);
    213 
    214     return TRUE;
    215 }
    216 
    217 static void
    218 translate_rect (struct QXLRect *rect)
    219 {
    220     rect->right -= rect->left;
    221     rect->bottom -= rect->top;
    222     rect->left = rect->top = 0;
    223 }
    224 
    225 static void
    226 real_upload_box (qxl_surface_t *surface, int x1, int y1, int x2, int y2)
    227 {
    228     struct QXLRect rect;
    229     struct QXLDrawable *drawable;
    230     struct qxl_bo *image_bo, *drawable_bo;
    231     qxl_screen_t *qxl = surface->qxl;
    232     uint32_t *data;
    233     int stride;
    234 
    235     rect.left = x1;
    236     rect.right = x2;
    237     rect.top = y1;
    238     rect.bottom = y2;
    239 
    240     drawable_bo = make_drawable (qxl, surface, QXL_DRAW_COPY, &rect);
    241     drawable = qxl->bo_funcs->bo_map(drawable_bo);
    242     drawable->u.copy.src_area = rect;
    243     translate_rect (&drawable->u.copy.src_area);
    244     drawable->u.copy.rop_descriptor = ROPD_OP_PUT;
    245     drawable->u.copy.scale_mode = 0;
    246     drawable->u.copy.mask.flags = 0;
    247     drawable->u.copy.mask.pos.x = 0;
    248     drawable->u.copy.mask.pos.y = 0;
    249     drawable->u.copy.mask.bitmap = 0;
    250 
    251     qxl->bo_funcs->bo_unmap(drawable_bo);
    252 
    253     data = pixman_image_get_data (surface->host_image);
    254     stride = pixman_image_get_stride (surface->host_image);
    255 
    256     image_bo = qxl_image_create (
    257 	qxl, (const uint8_t *)data, x1, y1, x2 - x1, y2 - y1, stride,
    258 	surface->bpp == 24 ? 4 : surface->bpp / 8, TRUE);
    259     qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.copy.src_bitmap),
    260 				   drawable_bo, image_bo);
    261     push_drawable (qxl, drawable_bo);
    262 
    263     qxl->bo_funcs->bo_decref(qxl, image_bo);
    264 }
    265 
    266 #define TILE_WIDTH 512
    267 #define TILE_HEIGHT 512
    268 
    269 void
    270 qxl_upload_box (qxl_surface_t *surface, int x1, int y1, int x2, int y2)
    271 {
    272     int tile_x1, tile_y1;
    273 
    274     for (tile_y1 = y1; tile_y1 < y2; tile_y1 += TILE_HEIGHT)
    275     {
    276 	for (tile_x1 = x1; tile_x1 < x2; tile_x1 += TILE_WIDTH)
    277 	{
    278 	    int tile_x2 = tile_x1 + TILE_WIDTH;
    279 	    int tile_y2 = tile_y1 + TILE_HEIGHT;
    280 
    281 	    if (tile_x2 > x2)
    282 		tile_x2 = x2;
    283 	    if (tile_y2 > y2)
    284 		tile_y2 = y2;
    285 
    286 	    real_upload_box (surface, tile_x1, tile_y1, tile_x2, tile_y2);
    287 	}
    288     }
    289 }
    290 
    291 static void
    292 upload_one_primary_region(qxl_screen_t *qxl, PixmapPtr pixmap, BoxPtr b)
    293 {
    294     struct QXLRect rect;
    295     struct qxl_bo *drawable_bo, *image_bo;
    296     struct QXLDrawable *drawable;
    297     FbBits *data;
    298     int stride;
    299     int bpp;
    300 
    301     if (b->x1 >= qxl->virtual_x || b->y1 >= qxl->virtual_y)
    302         return;
    303 
    304     rect.left = b->x1;
    305     rect.right = min(b->x2, qxl->virtual_x);
    306     rect.top = b->y1;
    307     rect.bottom = min(b->y2, qxl->virtual_y);
    308 
    309     drawable_bo = make_drawable (qxl, qxl->primary, QXL_DRAW_COPY, &rect);
    310     drawable = qxl->bo_funcs->bo_map(drawable_bo);
    311     drawable->u.copy.src_area = rect;
    312     translate_rect (&drawable->u.copy.src_area);
    313     drawable->u.copy.rop_descriptor = ROPD_OP_PUT;
    314     drawable->u.copy.scale_mode = 0;
    315     drawable->u.copy.mask.flags = 0;
    316     drawable->u.copy.mask.pos.x = 0;
    317     drawable->u.copy.mask.pos.y = 0;
    318     drawable->u.copy.mask.bitmap = 0;
    319     qxl->bo_funcs->bo_unmap(drawable_bo);
    320 
    321     fbGetPixmapBitsData(pixmap, data, stride, bpp);
    322     image_bo = qxl_image_create (
    323 	qxl, (const uint8_t *)data, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, stride * sizeof(*data),
    324 	bpp == 24 ? 4 : bpp / 8, TRUE);
    325     qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.copy.src_bitmap),
    326 				   drawable_bo, image_bo);
    327 
    328     push_drawable (qxl, drawable_bo);
    329     qxl->bo_funcs->bo_decref(qxl, image_bo);
    330 }
    331 
    332 void
    333 qxl_surface_upload_primary_regions(qxl_screen_t *qxl, PixmapPtr pixmap, RegionRec *r)
    334 {
    335     int n_boxes;
    336     BoxPtr boxes;
    337 
    338     n_boxes = RegionNumRects(r);
    339     boxes = RegionRects(r);
    340 
    341     while (n_boxes--)
    342     {
    343         upload_one_primary_region(qxl, pixmap, boxes);
    344         boxes++;
    345     }
    346 }
    347 
    348 void
    349 qxl_surface_finish_access (qxl_surface_t *surface, PixmapPtr pixmap)
    350 {
    351     ScreenPtr pScreen = pixmap->drawable.pScreen;
    352     int w = pixmap->drawable.width;
    353     int h = pixmap->drawable.height;
    354     int n_boxes;
    355     BoxPtr boxes;
    356 
    357     n_boxes = REGION_NUM_RECTS (&surface->access_region);
    358     boxes = REGION_RECTS (&surface->access_region);
    359 
    360     if (surface->access_type == UXA_ACCESS_RW)
    361     {
    362 	if (n_boxes < 25)
    363 	{
    364 	    while (n_boxes--)
    365 	    {
    366 		qxl_upload_box (surface, boxes->x1, boxes->y1, boxes->x2, boxes->y2);
    367 
    368 		boxes++;
    369 	    }
    370 	}
    371 	else
    372 	{
    373 	    qxl_upload_box (surface,
    374 			surface->access_region.extents.x1,
    375 			surface->access_region.extents.y1,
    376 			surface->access_region.extents.x2,
    377 			surface->access_region.extents.y2);
    378 	}
    379     }
    380 
    381     REGION_EMPTY (pScreen, &surface->access_region);
    382     surface->access_type = UXA_ACCESS_RO;
    383 
    384     pScreen->ModifyPixmapHeader(pixmap, w, h, -1, -1, 0, NULL);
    385 }
    386 
    387 
    388 #ifdef DEBUG_REGIONS
    389 static void
    390 print_region (const char *header, RegionPtr pRegion)
    391 {
    392     int nbox = REGION_NUM_RECTS (pRegion);
    393     BoxPtr pbox = REGION_RECTS (pRegion);
    394 
    395     ErrorF ("%s", header);
    396 
    397     if (nbox == 0)
    398 	ErrorF (" (empty)\n");
    399     else
    400 	ErrorF ("\n");
    401 
    402     while (nbox--)
    403     {
    404 	ErrorF ("   %d %d %d %d (size: %d %d)\n",
    405 		pbox->x1, pbox->y1, pbox->x2, pbox->y2,
    406 		pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
    407 
    408 	pbox++;
    409     }
    410 }
    411 #endif // DEBUG_REGIONS
    412 
    413 /* solid */
    414 Bool
    415 qxl_surface_prepare_solid (qxl_surface_t *destination,
    416 			   Pixel	  fg)
    417 {
    418     if (!REGION_NIL (&(destination->access_region)))
    419     {
    420 	ErrorF (" solid not in vmem\n");
    421     }
    422 
    423 #ifdef DEBUG_REGIONS
    424     print_region ("prepare solid", &(destination->access_region));
    425 #endif
    426 
    427     destination->u.solid_pixel = fg; //  ^ (rand() >> 16);
    428 
    429     return TRUE;
    430 }
    431 
    432 void
    433 qxl_surface_solid (qxl_surface_t *destination,
    434 		   int	          x1,
    435 		   int	          y1,
    436 		   int	          x2,
    437 		   int	          y2)
    438 {
    439     qxl_screen_t *qxl = destination->qxl;
    440     struct QXLRect qrect;
    441     uint32_t p;
    442 
    443     qrect.top = y1;
    444     qrect.bottom = y2;
    445     qrect.left = x1;
    446     qrect.right = x2;
    447 
    448     p = destination->u.solid_pixel;
    449 
    450     submit_fill (qxl, destination, &qrect, p);
    451 }
    452 
    453 /* copy */
    454 Bool
    455 qxl_surface_prepare_copy (qxl_surface_t *dest,
    456 			  qxl_surface_t *source)
    457 {
    458     if (!REGION_NIL (&(dest->access_region))	||
    459 	!REGION_NIL (&(source->access_region)))
    460     {
    461 	return FALSE;
    462     }
    463 
    464     dest->u.copy_src = source;
    465 
    466     return TRUE;
    467 }
    468 
    469 
    470 static struct qxl_bo *
    471 image_from_surface_internal(qxl_screen_t *qxl,
    472 			    qxl_surface_t *surface)
    473 {
    474     struct qxl_bo *image_bo = qxl->bo_funcs->bo_alloc (qxl, sizeof(struct QXLImage), "image struct for surface");
    475     struct QXLImage *image = qxl->bo_funcs->bo_map(image_bo);
    476 
    477     image->descriptor.id = 0;
    478     image->descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
    479     image->descriptor.width = 0;
    480     image->descriptor.height = 0;
    481     qxl->bo_funcs->bo_unmap(image_bo);
    482     return image_bo;
    483 }
    484 
    485 static struct qxl_bo *image_from_surface(qxl_screen_t *qxl, qxl_surface_t *dest)
    486 {
    487     if (!dest->image_bo)
    488       dest->image_bo = image_from_surface_internal(qxl, dest);
    489 
    490     qxl->bo_funcs->bo_incref(qxl, dest->image_bo);
    491     qxl->bo_funcs->bo_output_surf_reloc(qxl, offsetof(struct QXLImage, surface_image.surface_id), dest->image_bo, dest);
    492 
    493     return dest->image_bo;
    494 }
    495 
    496 void
    497 qxl_surface_copy (qxl_surface_t *dest,
    498 		  int  src_x1, int src_y1,
    499 		  int  dest_x1, int dest_y1,
    500 		  int width, int height)
    501 {
    502     qxl_screen_t *qxl = dest->qxl;
    503     struct qxl_bo *drawable_bo;
    504     struct QXLDrawable *drawable;
    505     struct QXLRect qrect;
    506 
    507 #ifdef DEBUG_REGIONS
    508     print_region (" copy src", &(dest->u.copy_src->access_region));
    509     print_region (" copy dest", &(dest->access_region));
    510 #endif
    511 
    512     qrect.top = dest_y1;
    513     qrect.bottom = dest_y1 + height;
    514     qrect.left = dest_x1;
    515     qrect.right = dest_x1 + width;
    516 
    517     if (dest->id == dest->u.copy_src->id)
    518     {
    519 	drawable_bo = make_drawable (qxl, dest, QXL_COPY_BITS, &qrect);
    520 
    521 	drawable = qxl->bo_funcs->bo_map(drawable_bo);
    522 	drawable->u.copy_bits.src_pos.x = src_x1;
    523 	drawable->u.copy_bits.src_pos.y = src_y1;
    524 	qxl->bo_funcs->bo_unmap(drawable_bo);
    525 
    526 	push_drawable (qxl, drawable_bo);
    527 
    528     }
    529     else
    530     {
    531 	struct qxl_bo *image_bo;
    532 
    533 	dest->u.copy_src->ref_count++;
    534 
    535 	image_bo = image_from_surface(qxl, dest->u.copy_src);
    536 
    537 	drawable_bo = make_drawable (qxl, dest, QXL_DRAW_COPY, &qrect);
    538 
    539 	drawable = qxl->bo_funcs->bo_map(drawable_bo);
    540 	qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.copy.src_bitmap),
    541 				       drawable_bo, image_bo);
    542 	drawable->u.copy.src_area.left = src_x1;
    543 	drawable->u.copy.src_area.top = src_y1;
    544 	drawable->u.copy.src_area.right = src_x1 + width;
    545 	drawable->u.copy.src_area.bottom = src_y1 + height;
    546 	drawable->u.copy.rop_descriptor = ROPD_OP_PUT;
    547 	drawable->u.copy.scale_mode = 0;
    548 	drawable->u.copy.mask.flags = 0;
    549 	drawable->u.copy.mask.pos.x = 0;
    550 	drawable->u.copy.mask.pos.y = 0;
    551 	drawable->u.copy.mask.bitmap = 0;
    552 
    553 	qxl->bo_funcs->bo_output_surf_reloc(qxl, offsetof(struct QXLDrawable, surfaces_dest[0]), drawable_bo, dest->u.copy_src);
    554 	drawable->surfaces_rects[0] = drawable->u.copy.src_area;
    555 
    556 	assert (src_x1 >= 0);
    557 	assert (src_y1 >= 0);
    558 
    559 	if (width > pixman_image_get_width (dest->u.copy_src->host_image))
    560 	{
    561 	    ErrorF ("dest w: %d   src w: %d\n",
    562 		    width, pixman_image_get_width (dest->u.copy_src->host_image));
    563 	}
    564 
    565 	assert (width <= pixman_image_get_width (dest->u.copy_src->host_image));
    566 	assert (height <= pixman_image_get_height (dest->u.copy_src->host_image));
    567 
    568 	qxl->bo_funcs->bo_unmap(drawable_bo);
    569 	push_drawable (qxl, drawable_bo);
    570 	qxl->bo_funcs->bo_decref(qxl, image_bo);
    571     }
    572 }
    573 
    574 /* composite */
    575 Bool
    576 qxl_surface_prepare_composite (int op,
    577 			       PicturePtr	src_picture,
    578 			       PicturePtr	mask_picture,
    579 			       PicturePtr	dest_picture,
    580 			       qxl_surface_t *	src,
    581 			       qxl_surface_t *	mask,
    582 			       qxl_surface_t *	dest)
    583 {
    584     dest->u.composite.op = op;
    585     dest->u.composite.src_picture = src_picture;
    586     dest->u.composite.mask_picture = mask_picture;
    587     dest->u.composite.dest_picture = dest_picture;
    588     dest->u.composite.src = src;
    589     dest->u.composite.mask = mask;
    590     dest->u.composite.dest = dest;
    591 
    592     return TRUE;
    593 }
    594 
    595 static struct qxl_bo *
    596 image_from_picture (qxl_screen_t *qxl,
    597 		    PicturePtr picture,
    598 		    qxl_surface_t *surface,
    599 		    int *force_opaque)
    600 {
    601     if (picture->format == PICT_x8r8g8b8)
    602 	*force_opaque = TRUE;
    603     else
    604 	*force_opaque = FALSE;
    605 
    606     return image_from_surface(qxl, surface);
    607 }
    608 
    609 static struct qxl_bo *
    610 get_transform (qxl_screen_t *qxl, PictTransform *transform)
    611 {
    612     if (transform)
    613     {
    614 	struct qxl_bo *qxform_bo = qxl->bo_funcs->bo_alloc (qxl, sizeof (QXLTransform), "transform");
    615 	QXLTransform *qxform = qxl->bo_funcs->bo_map(qxform_bo);
    616 
    617 	qxform->t00 = transform->matrix[0][0];
    618 	qxform->t01 = transform->matrix[0][1];
    619 	qxform->t02 = transform->matrix[0][2];
    620 	qxform->t10 = transform->matrix[1][0];
    621 	qxform->t11 = transform->matrix[1][1];
    622 	qxform->t12 = transform->matrix[1][2];
    623 
    624 	qxl->bo_funcs->bo_unmap(qxform_bo);
    625 	return qxform_bo;
    626     }
    627     else
    628     {
    629 	return NULL;
    630     }
    631 }
    632 
    633 static QXLRect
    634 full_rect (qxl_surface_t *surface)
    635 {
    636     QXLRect r;
    637     int w = pixman_image_get_width (surface->host_image);
    638     int h = pixman_image_get_height (surface->host_image);
    639 
    640     r.left = r.top = 0;
    641     r.right = w;
    642     r.bottom = h;
    643 
    644     return r;
    645 }
    646 
    647 void
    648 qxl_surface_composite (qxl_surface_t *dest,
    649 		       int src_x, int src_y,
    650 		       int mask_x, int mask_y,
    651 		       int dest_x, int dest_y,
    652 		       int width, int height)
    653 {
    654     qxl_screen_t *qxl = dest->qxl;
    655     PicturePtr src = dest->u.composite.src_picture;
    656     qxl_surface_t *qsrc = dest->u.composite.src;
    657     PicturePtr mask = dest->u.composite.mask_picture;
    658     qxl_surface_t *qmask = dest->u.composite.mask;
    659     int op = dest->u.composite.op;
    660     struct QXLDrawable *drawable;
    661     struct qxl_bo *drawable_bo;
    662     QXLComposite *composite;
    663     QXLRect rect;
    664     struct qxl_bo *trans_bo, *img_bo;
    665     int n_deps = 0;
    666     int force_opaque;
    667     struct qxl_bo *derefs[4];
    668     int n_derefs = 0, i;
    669 #if 0
    670     ErrorF ("QXL Composite: src:       %x (%d %d) id: %d; \n"
    671 	    "               mask:      id: %d\n"
    672 	    "               dest:      %x %d %d %d %d (id: %d)\n",
    673 	    dest->u.composite.src_picture->format,
    674 	    dest->u.composite.src_picture->pDrawable->width,
    675 	    dest->u.composite.src_picture->pDrawable->height,
    676 	    dest->u.composite.src->id,
    677 	    dest->u.composite.mask? dest->u.composite.mask->id : -1,
    678 	    dest->u.composite.dest_picture->format,
    679 	    dest_x, dest_y, width, height,
    680 	    dest->id
    681 	);
    682 #endif
    683 
    684     rect.left = dest_x;
    685     rect.right = dest_x + width;
    686     rect.top = dest_y;
    687     rect.bottom = dest_y + height;
    688 
    689     drawable_bo = make_drawable (qxl, dest, QXL_DRAW_COMPOSITE, &rect);
    690 
    691     drawable = qxl->bo_funcs->bo_map(drawable_bo);
    692 
    693     composite = &drawable->u.composite;
    694 
    695     composite->flags = 0;
    696 
    697     if (dest->u.composite.dest_picture->format == PICT_x8r8g8b8)
    698 	composite->flags |= SPICE_COMPOSITE_DEST_OPAQUE;
    699 
    700     composite->flags |= (op & 0xff);
    701 
    702     img_bo = image_from_picture (qxl, src, qsrc, &force_opaque);
    703     if (force_opaque)
    704 	composite->flags |= SPICE_COMPOSITE_SOURCE_OPAQUE;
    705     qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.composite.src),
    706 				   drawable_bo, img_bo);
    707     derefs[n_derefs++] = img_bo;
    708 
    709     composite->flags |= (src->filter << 8);
    710     composite->flags |= (src->repeat << 14);
    711     trans_bo = get_transform (qxl, src->transform);
    712     if (trans_bo) {
    713 	qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.composite.src_transform),
    714 				       drawable_bo, trans_bo);
    715 	derefs[n_derefs++] = trans_bo;
    716     } else
    717 	composite->src_transform = 0;
    718 
    719     qxl->bo_funcs->bo_output_surf_reloc(qxl, offsetof(struct QXLDrawable, surfaces_dest[n_deps]), drawable_bo, qsrc);
    720     drawable->surfaces_rects[n_deps] = full_rect (qsrc);
    721 
    722     n_deps++;
    723 
    724     if (mask)
    725     {
    726 	img_bo = image_from_picture (qxl, mask, qmask, &force_opaque);
    727 	if (force_opaque)
    728 	    composite->flags |= SPICE_COMPOSITE_MASK_OPAQUE;
    729 
    730 	qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.composite.mask),
    731 				       drawable_bo, img_bo);
    732 	derefs[n_derefs++] = img_bo;
    733 	composite->flags |= (mask->filter << 11);
    734 	composite->flags |= (mask->repeat << 16);
    735 	composite->flags |= (mask->componentAlpha << 18);
    736 
    737 	qxl->bo_funcs->bo_output_surf_reloc(qxl, offsetof(struct QXLDrawable, surfaces_dest[n_deps]), drawable_bo, qmask);
    738 	drawable->surfaces_rects[n_deps] = full_rect (qmask);
    739 	n_deps++;
    740 
    741 	trans_bo = get_transform (qxl, src->transform);
    742 	if (trans_bo) {
    743 	    qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.composite.mask_transform),
    744 					   drawable_bo, trans_bo);
    745 	    derefs[n_derefs++] = trans_bo;
    746 	}
    747 	else
    748 	  composite->mask_transform = 0;
    749     }
    750     else
    751     {
    752 	composite->mask = 0x00000000;
    753 	composite->mask_transform = 0x00000000;
    754     }
    755 
    756     qxl->bo_funcs->bo_output_surf_reloc(qxl, offsetof(struct QXLDrawable, surfaces_dest[n_deps]), drawable_bo, dest);
    757     drawable->surfaces_rects[n_deps] = full_rect (dest);
    758 
    759     composite->src_origin.x = src_x;
    760     composite->src_origin.y = src_y;
    761     composite->mask_origin.x = mask_x;
    762     composite->mask_origin.y = mask_y;
    763 
    764     drawable->effect = QXL_EFFECT_BLEND;
    765 
    766     qxl->bo_funcs->bo_unmap(drawable_bo);
    767     push_drawable (qxl, drawable_bo);
    768 
    769     for (i = 0; i < n_derefs; i++)
    770       qxl->bo_funcs->bo_decref(qxl, derefs[i]);
    771 }
    772 
    773 Bool
    774 qxl_surface_put_image (qxl_surface_t *dest,
    775 		       int x, int y, int width, int height,
    776 		       const char *src, int src_pitch)
    777 {
    778     struct qxl_bo *drawable_bo;
    779     struct QXLDrawable *drawable;
    780     qxl_screen_t *qxl = dest->qxl;
    781     struct QXLRect rect;
    782     struct qxl_bo *image_bo;
    783 
    784     rect.left = x;
    785     rect.right = x + width;
    786     rect.top = y;
    787     rect.bottom = y + height;
    788 
    789     drawable_bo = make_drawable (qxl, dest, QXL_DRAW_COPY, &rect);
    790 
    791     drawable = qxl->bo_funcs->bo_map(drawable_bo);
    792     drawable->u.copy.src_area.top = 0;
    793     drawable->u.copy.src_area.bottom = height;
    794     drawable->u.copy.src_area.left = 0;
    795     drawable->u.copy.src_area.right = width;
    796 
    797     drawable->u.copy.rop_descriptor = ROPD_OP_PUT;
    798     drawable->u.copy.scale_mode = 0;
    799     drawable->u.copy.mask.flags = 0;
    800     drawable->u.copy.mask.pos.x = 0;
    801     drawable->u.copy.mask.pos.y = 0;
    802     drawable->u.copy.mask.bitmap = 0;
    803 
    804     image_bo = qxl_image_create (
    805 	qxl, (const uint8_t *)src, 0, 0, width, height, src_pitch,
    806 	dest->bpp == 24 ? 4 : dest->bpp / 8, FALSE);
    807     qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(QXLDrawable, u.copy.src_bitmap),
    808 				   drawable_bo, image_bo);
    809 
    810     qxl->bo_funcs->bo_unmap(drawable_bo);
    811 
    812     push_drawable (qxl, drawable_bo);
    813     qxl->bo_funcs->bo_decref(qxl, image_bo);
    814     return TRUE;
    815 }
    816 
    817 void
    818 qxl_get_formats (int bpp, SpiceSurfaceFmt *format, pixman_format_code_t *pformat)
    819 {
    820     switch (bpp)
    821     {
    822     case 8:
    823 	*format = SPICE_SURFACE_FMT_8_A;
    824 	*pformat = PIXMAN_a8;
    825 	break;
    826 
    827     case 16:
    828 	*format = SPICE_SURFACE_FMT_16_565;
    829 	*pformat = PIXMAN_r5g6b5;
    830 	break;
    831 
    832     case 24:
    833 	*format = SPICE_SURFACE_FMT_32_xRGB;
    834 	*pformat = PIXMAN_a8r8g8b8;
    835 	break;
    836 
    837     case 32:
    838 	*format = SPICE_SURFACE_FMT_32_ARGB;
    839 	*pformat = PIXMAN_a8r8g8b8;
    840 	break;
    841 
    842     default:
    843 	*format = -1;
    844 	*pformat = -1;
    845 	break;
    846     }
    847 }
    848