summaryrefslogtreecommitdiff
path: root/src
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 /src
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.
Diffstat (limited to 'src')
-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,