diff options
author | Alexander Larsson <alexl@redhat.com> | 2010-04-21 13:08:52 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2010-04-23 16:39:13 +0200 |
commit | 774e5bd36f4fc156dd744a455ff7ddda27441568 (patch) | |
tree | cda4d3dcdb1f516a17ca5f74779f3ddbfc691f96 /client/x11/red_drawable.cpp | |
parent | d2a2f18b6e1b77bb6a04121455385d7e23e77168 (diff) | |
download | spice-774e5bd36f4fc156dd744a455ff7ddda27441568.tar.gz spice-774e5bd36f4fc156dd744a455ff7ddda27441568.tar.xz spice-774e5bd36f4fc156dd744a455ff7ddda27441568.zip |
Client: Support pixmap format conversion in copy_pixels
In order to be able to support 16bit canvases on 32bit screens and 32bit
canvases on 16bit screens we need to handle format conversion when drawing
RedPixmaps.
The way this works now for X11 is that we only have one PIXELS_SOURCE_TYPE
for pixmaps, which always has a pixman_image_t for the data, but additionally
it has an XImage (shared mem or not) if the screen the pixmap was created
for (i.e. an explicit one or the default screen) has the same format as
the pixmap.
When we draw a pixmap on a drawable we have two variants. If the pixmap
has a XImage and it matches the format of the target drawable then we
just X(Shm)PutImage it to the drawable. If the formats differ, then we
create a temporary XImage and convert into that before drawing it to
the screen.
Right now this is a bit inefficient, because we always allocate a new
temporary image when converting. We want to add some caching here, but
at least this lets things work again.
Diffstat (limited to 'client/x11/red_drawable.cpp')
-rw-r--r-- | client/x11/red_drawable.cpp | 145 |
1 files changed, 94 insertions, 51 deletions
diff --git a/client/x11/red_drawable.cpp b/client/x11/red_drawable.cpp index 94ae523a..32754da9 100644 --- a/client/x11/red_drawable.cpp +++ b/client/x11/red_drawable.cpp @@ -111,11 +111,11 @@ static inline void copy_to_gldrawable_from_pixmap(const RedDrawable_p* dest, glDisable(GL_TEXTURE_2D); } - glPixelStorei(GL_UNPACK_ROW_LENGTH, source->pixmap.x_image->bytes_per_line / 4); + glPixelStorei(GL_UNPACK_ROW_LENGTH, pixman_image_get_stride(source->pixmap.pixman_image) / 4); glPixelZoom(1, -1); - addr = (uint8_t *)source->pixmap.x_image->data; - addr += (src_x * 4 + src_y * source->pixmap.x_image->bytes_per_line); + addr = (uint8_t *)pixman_image_get_data(source->pixmap.pixman_image); + addr += (src_x * 4 + src_y * pixman_image_get_stride(source->pixmap.pixman_image)); glWindowPos2i(area.left + offset.x, dest->source.x_drawable.height - (area.top + offset.y)); //+ (area.bottom - area.top))); glDrawPixels(area.right - area.left, area.bottom - area.top, @@ -149,37 +149,106 @@ static inline void copy_to_drawable_from_drawable(const RedDrawable_p* dest, area.left + offset.x, area.top + offset.y); } +static XImage *create_temp_image(int screen, int width, int height, + pixman_image_t **pixman_image_out, + XShmSegmentInfo **shminfo_out) +{ + XImage *image; + XShmSegmentInfo *shminfo; + RedDrawable::Format format; + pixman_image_t *pixman_image; + XVisualInfo *vinfo; + + image = NULL; + shminfo = NULL; + + vinfo = XPlatform::get_vinfo()[screen]; + format = XPlatform::get_screen_format(screen); + + image = XPlatform::create_x_image(format, width, height, vinfo->depth, + vinfo->visual, &shminfo); + + pixman_image = pixman_image_create_bits(RedDrawable::format_to_pixman(format), + width, height, + (uint32_t *)image->data, image->bytes_per_line); + if (pixman_image == NULL) { + THROW("surf create failed"); + } + *pixman_image_out = pixman_image; + *shminfo_out = shminfo; + return image; +} + +static void free_temp_image(XImage *image, XShmSegmentInfo *shminfo, pixman_image_t *pixman_image) +{ + XPlatform::free_x_image(image, shminfo); + pixman_image_unref(pixman_image); +} + + static inline void copy_to_drawable_from_pixmap(const RedDrawable_p* dest, const SpiceRect& area, const SpicePoint& offset, const PixelsSource_p* source, int src_x, int src_y) { + pixman_image_t *src_surface = source->pixmap.pixman_image; XGCValues gc_vals; gc_vals.function = GXcopy; + RedDrawable::Format screen_format; + XImage *image; + XShmSegmentInfo *shminfo; + pixman_image_t *pixman_image; + int screen; + + screen = dest->source.x_drawable.screen; + screen_format = XPlatform::get_screen_format(screen); XChangeGC(XPlatform::get_display(), dest->source.x_drawable.gc, GCFunction, &gc_vals); - XPutImage(XPlatform::get_display(), dest->source.x_drawable.drawable, - dest->source.x_drawable.gc, source->pixmap.x_image, src_x, - src_y, area.left + offset.x, area.top + offset.y, - area.right - area.left, area.bottom - area.top); -} -static inline void copy_to_drawable_from_shmdrawable(const RedDrawable_p* dest, - const SpiceRect& area, - const SpicePoint& offset, - const PixelsSource_p* source, - int src_x, int src_y) -{ - XGCValues gc_vals; - gc_vals.function = GXcopy; + if (source->pixmap.x_image != NULL && + RedDrawable::format_copy_compatible(source->pixmap.format, screen_format)) { + if (source->pixmap.shminfo) { + XShmPutImage(XPlatform::get_display(), dest->source.x_drawable.drawable, + dest->source.x_drawable.gc, source->pixmap.x_image, + src_x, src_y, area.left + offset.x, area.top + offset.y, + area.right - area.left, area.bottom - area.top, false); + XSync(XPlatform::get_display(), 0); + } else { + XPutImage(XPlatform::get_display(), dest->source.x_drawable.drawable, + dest->source.x_drawable.gc, source->pixmap.x_image, src_x, + src_y, area.left + offset.x, area.top + offset.y, + area.right - area.left, area.bottom - area.top); + } + } else { + image = create_temp_image(screen, + area.right - area.left, area.bottom - area.top, + &pixman_image, &shminfo); - XChangeGC(XPlatform::get_display(), dest->source.x_drawable.gc, GCFunction, &gc_vals); - XShmPutImage(XPlatform::get_display(), dest->source.x_drawable.drawable, - dest->source.x_drawable.gc, source->x_shm_drawable.x_image, - src_x, src_y, area.left + offset.x, area.top + offset.y, - area.right - area.left, area.bottom - area.top, false); - XSync(XPlatform::get_display(), 0); + pixman_image_composite32(PIXMAN_OP_SRC, + src_surface, NULL, pixman_image, + src_x + offset.x, + src_y + offset.y, + 0, 0, + 0, 0, + area.right - area.left, + area.bottom - area.top); + + if (shminfo) { + XShmPutImage(XPlatform::get_display(), dest->source.x_drawable.drawable, + dest->source.x_drawable.gc, image, + 0, 0, area.left + offset.x, area.top + offset.y, + area.right - area.left, area.bottom - area.top, false); + XSync(XPlatform::get_display(), 0); + } else { + XPutImage(XPlatform::get_display(), dest->source.x_drawable.drawable, + dest->source.x_drawable.gc, image, + 0, 0, area.left + offset.x, area.top + offset.y, + area.right - area.left, area.bottom - area.top); + } + + free_temp_image(image, shminfo, pixman_image); + } } static inline void copy_to_x_drawable(const RedDrawable_p* dest, @@ -195,9 +264,6 @@ static inline void copy_to_x_drawable(const RedDrawable_p* dest, case PIXELS_SOURCE_TYPE_PIXMAP: copy_to_drawable_from_pixmap(dest, area, offset, source, src_x, src_y); break; - case PIXELS_SOURCE_TYPE_XSHM_DRAWABLE: - copy_to_drawable_from_shmdrawable(dest, area, offset, source, src_x, src_y); - break; default: THROW("invalid source type %d", source->type); } @@ -230,26 +296,6 @@ static inline void copy_to_pixmap_from_drawable(const RedDrawable_p* dest, LOG_WARN("not implemented"); } -static inline void copy_to_pixmap_from_shmdrawable(const RedDrawable_p* dest, - const SpiceRect& area, - const SpicePoint& offset, - const PixelsSource_p* source, - int src_x, int src_y) -{ - pixman_image_t *dest_surface = dest->source.pixmap.pixman_image; - pixman_image_t *src_surface = source->x_shm_drawable.pixman_image; - - pixman_image_composite32(PIXMAN_OP_SRC, - src_surface, NULL, dest_surface, - src_x + offset.x, - src_y + offset.y, - 0, 0, - area.left + offset.x, - area.top + offset.y, - area.right - area.left, - area.bottom - area.top); -} - static inline void copy_to_pixmap_from_pixmap(const RedDrawable_p* dest, const SpiceRect& area, const SpicePoint& offset, @@ -297,15 +343,15 @@ static inline void copy_to_pixmap_from_gltexture(const RedDrawable_p* dest, } glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); glPixelStorei(GL_PACK_ROW_LENGTH, - dest->source.pixmap.x_image->bytes_per_line / 4); + pixman_image_get_stride(dest->source.pixmap.pixman_image) / 4); while (height > 0) { glReadPixels(src_x, y - height, area.right - area.left, 1, GL_BGRA, GL_UNSIGNED_BYTE, - dest->source.pixmap.x_image->data + + (uint8_t *)pixman_image_get_stride(dest->source.pixmap.pixman_image) + (area.left + offset.x) * 4 + (area.top + offset.y + height - 1) * - dest->source.pixmap.x_image->bytes_per_line); + pixman_image_get_stride(dest->source.pixmap.pixman_image)); height--; } if (rendertype != RENDER_TYPE_FBO) { @@ -330,9 +376,6 @@ static inline void copy_to_pixmap(const RedDrawable_p* dest, case PIXELS_SOURCE_TYPE_PIXMAP: copy_to_pixmap_from_pixmap(dest, area, offset, source, src_x, src_y); break; - case PIXELS_SOURCE_TYPE_XSHM_DRAWABLE: - copy_to_pixmap_from_shmdrawable(dest, area, offset, source, src_x, src_y); - break; default: THROW("invalid source type %d", source->type); } |