summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann <ssp@redhat.com>2012-07-12 09:53:31 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2012-09-05 18:17:25 -0400
commit7059cff787eef80f3d3345de705e912b292a9f97 (patch)
tree66f9f993cfecd47864164e81f4af7f05e73f18ba
parent2fecf3a171e64ca0dad5653ed740409dc5af2edf (diff)
Add Render support
This commit adds support for using the new Composite command in spice protocol 0.12.0. This command is similar to the Composite request in the X Render protocol. By implementing the UXA composite stubs, we get acceleration for most common Composite requests, including glyphs.
-rw-r--r--src/qxl.h16
-rw-r--r--src/qxl_driver.c193
-rw-r--r--src/qxl_image.c4
-rw-r--r--src/qxl_surface.c201
4 files changed, 390 insertions, 24 deletions
diff --git a/src/qxl.h b/src/qxl.h
index d976fd5..8494550 100644
--- a/src/qxl.h
+++ b/src/qxl.h
@@ -392,7 +392,21 @@ Bool qxl_surface_put_image (qxl_surface_t *dest,
const char *src, int src_pitch);
void qxl_surface_unref (surface_cache_t *cache,
uint32_t surface_id);
-
+
+/* composite */
+Bool qxl_surface_prepare_composite (int op,
+ PicturePtr src_picture,
+ PicturePtr mask_picture,
+ PicturePtr dst_picture,
+ qxl_surface_t *src,
+ qxl_surface_t *mask,
+ qxl_surface_t *dest);
+void qxl_surface_composite (qxl_surface_t *dest,
+ int src_x, int src_y,
+ int mask_x, int mask_y,
+ int dst_x, int dst_y,
+ int width, int height);
+
#if HAS_DEVPRIVATEKEYREC
extern DevPrivateKeyRec uxa_pixmap_index;
#else
diff --git a/src/qxl_driver.c b/src/qxl_driver.c
index 634f181..c7b8486 100644
--- a/src/qxl_driver.c
+++ b/src/qxl_driver.c
@@ -339,14 +339,14 @@ qxl_garbage_collect_internal (qxl_screen_t *qxl, uint64_t id)
int is_cursor = FALSE;
int is_surface = FALSE;
int is_drawable = FALSE;
-
+
if ((id & POINTER_MASK) == 1)
is_cursor = TRUE;
else if ((id & POINTER_MASK) == 2)
is_surface = TRUE;
else
is_drawable = TRUE;
-
+
if (is_cursor && cmd->type == QXL_CURSOR_SET)
{
struct QXLCursor *cursor = (void *)virtual_address (
@@ -358,7 +358,7 @@ qxl_garbage_collect_internal (qxl_screen_t *qxl, uint64_t id)
{
struct QXLImage *image = virtual_address (
qxl, u64_to_pointer (drawable->u.copy.src_bitmap), qxl->main_mem_slot);
-
+
if (image->descriptor.type == SPICE_IMAGE_TYPE_SURFACE)
{
qxl_surface_unref (qxl->surface_cache, image->surface_image.surface_id);
@@ -370,16 +370,50 @@ qxl_garbage_collect_internal (qxl_screen_t *qxl, uint64_t id)
qxl_image_destroy (qxl, image);
}
}
+ else if (is_drawable && drawable->type == QXL_DRAW_COMPOSITE)
+ {
+ struct QXLTransform *src_trans, *mask_trans;
+ struct QXLImage *src_img, *mask_img;
+ 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");
+
+ 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");
+ }
+
+ /* Mask */
+ if (drawable->u.composite.mask)
+ {
+ 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");
+ }
+
+ mask_img = virtual_address (
+ qxl, u64_to_pointer (drawable->u.composite.mask), qxl->main_mem_slot);
+ qxl_free (qxl->mem, mask_img, "image struct");
+ }
+ }
else if (is_surface && surface_cmd->type == QXL_SURFACE_CMD_DESTROY)
{
qxl_surface_recycle (qxl->surface_cache, surface_cmd->surface_id);
qxl_surface_cache_sanity_check (qxl->surface_cache);
}
-
+
id = info->next;
-
+
qxl_free (qxl->mem, info, "command");
-
+
return id;
}
@@ -1198,12 +1232,6 @@ int uxa_pixmap_index;
#endif
static Bool
-unaccel (void)
-{
- return FALSE;
-}
-
-static Bool
qxl_prepare_access (PixmapPtr pixmap, RegionPtr region, uxa_access_t access)
{
return qxl_surface_prepare_access (get_surface (pixmap),
@@ -1312,6 +1340,131 @@ qxl_done_copy (PixmapPtr dest)
{
}
+/*
+ * Composite
+ */
+static Bool
+can_accelerate_picture (PicturePtr pict)
+{
+ if (!pict)
+ return TRUE;
+
+ if (pict->format != PICT_a8r8g8b8 &&
+ pict->format != PICT_x8r8g8b8 &&
+ pict->format != PICT_a8)
+ {
+ return FALSE;
+ }
+
+ if (!pict->pDrawable)
+ return FALSE;
+
+ if (pict->transform)
+ {
+ if (pict->transform->matrix[2][0] != 0 ||
+ pict->transform->matrix[2][1] != 0 ||
+ pict->transform->matrix[2][2] != pixman_int_to_fixed (1))
+ {
+ return FALSE;
+ }
+ }
+
+ if (pict->filter != PictFilterBilinear &&
+ pict->filter != PictFilterNearest)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static Bool
+qxl_check_composite (int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture,
+ int width, int height)
+{
+ int i;
+
+ static const int accelerated_ops[] =
+ {
+ PictOpClear, PictOpSrc, PictOpDst, PictOpOver, PictOpOverReverse,
+ PictOpIn, PictOpInReverse, PictOpOut, PictOpOutReverse,
+ PictOpAtop, PictOpAtopReverse, PictOpXor, PictOpAdd,
+ PictOpSaturate, PictOpMultiply, PictOpScreen, PictOpOverlay,
+ PictOpDarken, PictOpLighten, PictOpColorDodge, PictOpColorBurn,
+ PictOpHardLight, PictOpSoftLight, PictOpDifference, PictOpExclusion,
+ PictOpHSLHue, PictOpHSLSaturation, PictOpHSLColor, PictOpHSLLuminosity,
+ };
+
+ if (!can_accelerate_picture (pSrcPicture) ||
+ !can_accelerate_picture (pMaskPicture) ||
+ !can_accelerate_picture (pDstPicture))
+ {
+ return FALSE;
+ }
+
+ for (i = 0; i < sizeof (accelerated_ops) / sizeof (accelerated_ops[0]); ++i)
+ {
+ if (accelerated_ops[i] == op)
+ goto found;
+ }
+ return FALSE;
+
+found:
+ return TRUE;
+}
+
+static Bool
+qxl_check_composite_target (PixmapPtr pixmap)
+{
+ return TRUE;
+}
+
+static Bool
+qxl_check_composite_texture (ScreenPtr screen,
+ PicturePtr pPicture)
+{
+ return TRUE;
+}
+
+static Bool
+qxl_prepare_composite (int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture,
+ PixmapPtr pSrc,
+ PixmapPtr pMask,
+ PixmapPtr pDst)
+{
+ return qxl_surface_prepare_composite (
+ op, pSrcPicture, pMaskPicture, pDstPicture,
+ get_surface (pSrc),
+ pMask? get_surface (pMask) : NULL,
+ get_surface (pDst));
+}
+
+static void
+qxl_composite (PixmapPtr pDst,
+ int src_x, int src_y,
+ int mask_x, int mask_y,
+ int dst_x, int dst_y,
+ int width, int height)
+{
+ qxl_surface_composite (
+ get_surface (pDst),
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y, width, height);
+}
+
+static void
+qxl_done_composite (PixmapPtr pDst)
+{
+ ;
+}
+
static Bool
qxl_put_image (PixmapPtr pDst, int x, int y, int w, int h,
char *src, int src_pitch)
@@ -1453,12 +1606,12 @@ setup_uxa (qxl_screen_t *qxl, ScreenPtr screen)
qxl->uxa->done_copy = qxl_done_copy;
/* Composite */
- qxl->uxa->check_composite = (typeof (qxl->uxa->check_composite))unaccel;
- qxl->uxa->check_composite_target = (typeof (qxl->uxa->check_composite_target))unaccel;
- qxl->uxa->check_composite_texture = (typeof (qxl->uxa->check_composite_texture))unaccel;
- qxl->uxa->prepare_composite = (typeof (qxl->uxa->prepare_composite))unaccel;
- qxl->uxa->composite = (typeof (qxl->uxa->composite))unaccel;
- qxl->uxa->done_composite = (typeof (qxl->uxa->done_composite))unaccel;
+ qxl->uxa->check_composite = qxl_check_composite;
+ qxl->uxa->check_composite_target = qxl_check_composite_target;
+ qxl->uxa->check_composite_texture = qxl_check_composite_texture;
+ qxl->uxa->prepare_composite = qxl_prepare_composite;
+ qxl->uxa->composite = qxl_composite;
+ qxl->uxa->done_composite = qxl_done_composite;
/* PutImage */
qxl->uxa->put_image = qxl_put_image;
@@ -1625,6 +1778,10 @@ qxl_screen_init (SCREEN_INIT_ARGS_DECL)
pScreen->SaveScreen = qxl_blank_screen;
setup_uxa (qxl, pScreen);
+
+#if 0
+ uxa_set_fallback_debug(pScreen, TRUE);
+#endif
DamageSetup (pScreen);
diff --git a/src/qxl_image.c b/src/qxl_image.c
index 4d9bc77..fcecf8a 100644
--- a/src/qxl_image.c
+++ b/src/qxl_image.c
@@ -138,7 +138,7 @@ qxl_image_create (qxl_screen_t *qxl, const uint8_t *data,
struct QXLImage *image;
struct QXLDataChunk *head;
struct QXLDataChunk *tail;
- int dest_stride = width * Bpp;
+ int dest_stride = (width * Bpp + 3) & (~3);
int h;
data += y * stride + x * Bpp;
@@ -216,7 +216,7 @@ qxl_image_create (qxl_screen_t *qxl, const uint8_t *data,
image->bitmap.flags = SPICE_BITMAP_FLAGS_TOP_DOWN;
image->bitmap.x = width;
image->bitmap.y = height;
- image->bitmap.stride = width * Bpp;
+ image->bitmap.stride = dest_stride;
image->bitmap.palette = 0;
image->bitmap.data = physical_address (qxl, head, qxl->main_mem_slot);
diff --git a/src/qxl_surface.c b/src/qxl_surface.c
index 0169350..e88675f 100644
--- a/src/qxl_surface.c
+++ b/src/qxl_surface.c
@@ -89,6 +89,17 @@ struct qxl_surface_t
{
qxl_surface_t *copy_src;
Pixel solid_pixel;
+
+ struct
+ {
+ int op;
+ PicturePtr src_picture;
+ PicturePtr mask_picture;
+ PicturePtr dest_picture;
+ qxl_surface_t *src;
+ qxl_surface_t *mask;
+ qxl_surface_t *dest;
+ } composite;
} u;
};
@@ -302,7 +313,7 @@ get_formats (int bpp, SpiceBitmapFmt *format, pixman_format_code_t *pformat)
break;
}
}
-
+
static qxl_surface_t *
surface_get_from_cache (surface_cache_t *cache, int width, int height, int bpp)
{
@@ -674,7 +685,8 @@ retry:
push_surface_cmd (cache, cmd);
- dev_addr = (uint32_t *)((uint8_t *)surface->address + stride * (height - 1));
+ dev_addr
+ = (uint32_t *)((uint8_t *)surface->address + stride * (height - 1));
surface->dev_image = pixman_image_create_bits (
pformat, width, height, dev_addr, - stride);
@@ -735,7 +747,7 @@ qxl_surface_create (surface_cache_t * cache,
if (!(surface = surface_get_from_cache (cache, width, height, bpp)))
if (!(surface = surface_send_create (cache, width, height, bpp)))
return NULL;
-
+
surface->next = cache->live_surfaces;
surface->prev = NULL;
if (cache->live_surfaces)
@@ -1367,6 +1379,189 @@ qxl_surface_copy (qxl_surface_t *dest,
push_drawable (qxl, drawable);
}
+/* composite */
+Bool
+qxl_surface_prepare_composite (int op,
+ PicturePtr src_picture,
+ PicturePtr mask_picture,
+ PicturePtr dest_picture,
+ qxl_surface_t * src,
+ qxl_surface_t * mask,
+ qxl_surface_t * dest)
+{
+ dest->u.composite.op = op;
+ dest->u.composite.src_picture = src_picture;
+ dest->u.composite.mask_picture = mask_picture;
+ dest->u.composite.dest_picture = dest_picture;
+ dest->u.composite.src = src;
+ dest->u.composite.mask = mask;
+ dest->u.composite.dest = dest;
+
+ return TRUE;
+}
+
+static QXLImage *
+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");
+
+ image->descriptor.id = 0;
+ image->descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
+ image->descriptor.width = 0;
+ image->descriptor.height = 0;
+ image->surface_image.surface_id = surface->id;
+
+ if (picture->format == PICT_x8r8g8b8)
+ *force_opaque = TRUE;
+ else
+ *force_opaque = FALSE;
+
+ return image;
+}
+
+static QXLTransform *
+get_transform (qxl_screen_t *qxl, PictTransform *transform)
+{
+ if (transform)
+ {
+ QXLTransform *qxform = qxl_allocnf (qxl, sizeof (QXLTransform), "transform");
+
+ qxform->t00 = transform->matrix[0][0];
+ qxform->t01 = transform->matrix[0][1];
+ qxform->t02 = transform->matrix[0][2];
+ qxform->t10 = transform->matrix[1][0];
+ qxform->t11 = transform->matrix[1][1];
+ qxform->t12 = transform->matrix[1][2];
+
+ return qxform;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+static QXLRect
+full_rect (qxl_surface_t *surface)
+{
+ QXLRect r;
+ int w = pixman_image_get_width (surface->host_image);
+ int h = pixman_image_get_height (surface->host_image);
+
+ r.left = r.top = 0;
+ r.right = w;
+ r.bottom = h;
+
+ return r;
+}
+
+void
+qxl_surface_composite (qxl_surface_t *dest,
+ int src_x, int src_y,
+ int mask_x, int mask_y,
+ int dest_x, int dest_y,
+ int width, int height)
+{
+ qxl_screen_t *qxl = dest->cache->qxl;
+ PicturePtr src = dest->u.composite.src_picture;
+ qxl_surface_t *qsrc = dest->u.composite.src;
+ PicturePtr mask = dest->u.composite.mask_picture;
+ qxl_surface_t *qmask = dest->u.composite.mask;
+ int op = dest->u.composite.op;
+ struct QXLDrawable *drawable;
+ QXLComposite *composite;
+ QXLRect rect;
+ QXLImage *img;
+ QXLTransform *trans;
+ int n_deps = 0;
+ int force_opaque;
+
+#if 0
+ ErrorF ("QXL Composite: src: %x (%d %d) id: %d; \n"
+ " mask: id: %d\n"
+ " dest: %x %d %d %d %d (id: %d)\n",
+ dest->u.composite.src_picture->format,
+ dest->u.composite.src_picture->pDrawable->width,
+ dest->u.composite.src_picture->pDrawable->height,
+ dest->u.composite.src->id,
+ dest->u.composite.mask? dest->u.composite.mask->id : -1,
+ dest->u.composite.dest_picture->format,
+ dest_x, dest_y, width, height,
+ dest->id
+ );
+#endif
+
+ rect.left = dest_x;
+ rect.right = dest_x + width;
+ rect.top = dest_y;
+ rect.bottom = dest_y + height;
+
+ drawable = make_drawable (qxl, dest->id, QXL_DRAW_COMPOSITE, &rect);
+
+ composite = &drawable->u.composite;
+
+ composite->flags = 0;
+
+ if (dest->u.composite.dest_picture->format == PICT_x8r8g8b8)
+ composite->flags |= SPICE_COMPOSITE_DEST_OPAQUE;
+
+ composite->flags |= (op & 0xff);
+
+ img = 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);
+ 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;
+ drawable->surfaces_rects[n_deps] = full_rect (qsrc);
+
+ n_deps++;
+
+ if (mask)
+ {
+ img = 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);
+ composite->flags |= (mask->filter << 11);
+ composite->flags |= (mask->repeat << 16);
+ composite->flags |= (mask->componentAlpha << 18);
+
+ drawable->surfaces_dest[n_deps] = qmask->id;
+ 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;
+ }
+ else
+ {
+ composite->mask = 0x00000000;
+ composite->mask_transform = 0x00000000;
+ }
+
+ drawable->surfaces_dest[n_deps] = dest->id;
+ drawable->surfaces_rects[n_deps] = full_rect (dest);
+
+ composite->src_origin.x = src_x;
+ composite->src_origin.y = src_y;
+ composite->mask_origin.x = mask_x;
+ composite->mask_origin.y = mask_y;
+
+ drawable->effect = QXL_EFFECT_BLEND;
+
+ push_drawable (qxl, drawable);
+}
+
Bool
qxl_surface_put_image (qxl_surface_t *dest,
int x, int y, int width, int height,