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
31enum 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
46static struct qxl_bo *
47make_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
97static void
98push_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
103static void
104submit_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
126void
127qxl_surface_flush (qxl_surface_t *surface)
128{
129    ;
130}
131
132/* access */
133static void
134download_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
143void
144qxl_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
156Bool
157qxl_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
217static void
218translate_rect (struct QXLRect *rect)
219{
220    rect->right -= rect->left;
221    rect->bottom -= rect->top;
222    rect->left = rect->top = 0;
223}
224
225static void
226real_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
269void
270qxl_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
291static void
292upload_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
332void
333qxl_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
348void
349qxl_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
389static void
390print_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 */
414Bool
415qxl_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
432void
433qxl_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 */
454Bool
455qxl_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
470static struct qxl_bo *
471image_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
485static 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
496void
497qxl_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 */
575Bool
576qxl_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
595static struct qxl_bo *
596image_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
609static struct qxl_bo *
610get_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
633static QXLRect
634full_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
647void
648qxl_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
773Bool
774qxl_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
817void
818qxl_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