From 7059cff787eef80f3d3345de705e912b292a9f97 Mon Sep 17 00:00:00 2001 From: Søren Sandmann Date: Thu, 12 Jul 2012 09:53:31 -0400 Subject: 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. --- src/qxl.h | 16 ++++- src/qxl_driver.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++----- src/qxl_image.c | 4 +- src/qxl_surface.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 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; } @@ -1197,12 +1231,6 @@ DevPrivateKeyRec uxa_pixmap_index; int uxa_pixmap_index; #endif -static Bool -unaccel (void) -{ - return FALSE; -} - static Bool qxl_prepare_access (PixmapPtr pixmap, RegionPtr region, uxa_access_t access) { @@ -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, -- cgit v1.2.3