diff options
Diffstat (limited to 'client/x11')
-rw-r--r-- | client/x11/pixels_source.cpp | 70 | ||||
-rw-r--r-- | client/x11/pixels_source_p.h | 8 | ||||
-rw-r--r-- | client/x11/red_drawable.cpp | 145 | ||||
-rw-r--r-- | client/x11/red_pixmap_cairo.cpp | 186 | ||||
-rw-r--r-- | client/x11/red_window.cpp | 1 |
5 files changed, 170 insertions, 240 deletions
diff --git a/client/x11/pixels_source.cpp b/client/x11/pixels_source.cpp index 0ec39bdf..a2d49f39 100644 --- a/client/x11/pixels_source.cpp +++ b/client/x11/pixels_source.cpp @@ -24,50 +24,28 @@ #include "res.h" -static void create_image(const PixmapHeader* pixmap, PixelsSource_p& pixels_source, +static void create_pixmap(const PixmapHeader* pixmap, PixelsSource_p& pixels_source, pixman_format_code_t format) { pixman_image_t *pixman_image; - XImage *image = new XImage; - - memset(image, 0, sizeof(*image)); - image->width = pixmap->width; - image->height = pixmap->height; - - image->data = (char*)pixmap->data; - image->byte_order = LSBFirst; - image->bitmap_unit = 32; - image->bitmap_bit_order = LSBFirst; - image->bitmap_pad = 32; - image->bytes_per_line = pixmap->stride; - - image->depth = XPlatform::get_vinfo()[0]->depth; - image->format = ZPixmap; - image->bits_per_pixel = 32; - image->red_mask = 0x00ff0000; - image->green_mask = 0x0000ff00; - image->blue_mask = 0x000000ff; - - try { - if (!XInitImage(image)) { - THROW("init image failed"); - } - - pixman_image = pixman_image_create_bits(format, - pixmap->width, pixmap->height, - (uint32_t *)pixmap->data, - pixmap->stride); - if (pixman_image == NULL) { - THROW("surf create failed"); - } - } catch (...) { - delete image; - throw; + + pixman_image = pixman_image_create_bits(format, + pixmap->width, pixmap->height, + (uint32_t *)pixmap->data, + pixmap->stride); + if (pixman_image == NULL) { + THROW("surf create failed"); } pixels_source.type = PIXELS_SOURCE_TYPE_PIXMAP; - pixels_source.pixmap.x_image = image; pixels_source.pixmap.pixman_image = pixman_image; + pixels_source.pixmap.x_image = NULL; + pixels_source.pixmap.shminfo = NULL; + if (format == PIXMAN_a8r8g8b8) { + pixels_source.pixmap.format = RedDrawable::ARGB32; + } else { + pixels_source.pixmap.format = RedDrawable::RGB32; + } } PixelsSource::PixelsSource() @@ -86,21 +64,20 @@ ImageFromRes::ImageFromRes(int res_id) if (!pixmap) { THROW("no image %d", res_id); } - create_image(pixmap, *(PixelsSource_p*)get_opaque(), PIXMAN_x8r8g8b8); + create_pixmap(pixmap, *(PixelsSource_p*)get_opaque(), PIXMAN_x8r8g8b8); } ImageFromRes::~ImageFromRes() { pixman_image_unref(((PixelsSource_p*)get_opaque())->pixmap.pixman_image); - delete ((PixelsSource_p*)get_opaque())->pixmap.x_image; } SpicePoint ImageFromRes::get_size() { - XImage *image = ((PixelsSource_p*)get_opaque())->pixmap.x_image; + pixman_image_t *image = ((PixelsSource_p*)get_opaque())->pixmap.pixman_image; SpicePoint pt; - pt.x = image->width; - pt.y = image->height; + pt.x = pixman_image_get_width(image); + pt.y = pixman_image_get_height(image); return pt; } @@ -110,21 +87,20 @@ AlphaImageFromRes::AlphaImageFromRes(int res_id) if (!pixmap) { THROW("no image %d", res_id); } - create_image(pixmap, *(PixelsSource_p*)get_opaque(), PIXMAN_a8r8g8b8); + create_pixmap(pixmap, *(PixelsSource_p*)get_opaque(), PIXMAN_a8r8g8b8); } AlphaImageFromRes::~AlphaImageFromRes() { pixman_image_unref(((PixelsSource_p*)get_opaque())->pixmap.pixman_image); - delete ((PixelsSource_p*)get_opaque())->pixmap.x_image; } SpicePoint AlphaImageFromRes::get_size() { - XImage *image = ((PixelsSource_p*)get_opaque())->pixmap.x_image; + pixman_image_t *image = ((PixelsSource_p*)get_opaque())->pixmap.pixman_image; SpicePoint pt; - pt.x = image->width; - pt.y = image->height; + pt.x = pixman_image_get_width(image); + pt.y = pixman_image_get_height(image); return pt; } diff --git a/client/x11/pixels_source_p.h b/client/x11/pixels_source_p.h index 050c19a6..a3e4cfbc 100644 --- a/client/x11/pixels_source_p.h +++ b/client/x11/pixels_source_p.h @@ -28,7 +28,6 @@ enum { PIXELS_SOURCE_TYPE_INVALID, PIXELS_SOURCE_TYPE_X_DRAWABLE, - PIXELS_SOURCE_TYPE_XSHM_DRAWABLE, PIXELS_SOURCE_TYPE_PIXMAP, PIXELS_SOURCE_TYPE_GL_TEXTURE, PIXELS_SOURCE_TYPE_GL_DRAWABLE, @@ -39,6 +38,7 @@ struct PixelsSource_p { union { struct { Drawable drawable; + int screen; GC gc; int width, height; RenderType rendertype; @@ -53,11 +53,7 @@ struct PixelsSource_p { XImage* x_image; XShmSegmentInfo *shminfo; pixman_image_t* pixman_image; - } x_shm_drawable; - - struct { - XImage* x_image; - pixman_image_t* pixman_image; + RedDrawable::Format format; } pixmap; struct { 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); } diff --git a/client/x11/red_pixmap_cairo.cpp b/client/x11/red_pixmap_cairo.cpp index 1974ebc4..863ed392 100644 --- a/client/x11/red_pixmap_cairo.cpp +++ b/client/x11/red_pixmap_cairo.cpp @@ -22,156 +22,70 @@ #include "utils.h" #include "pixels_source_p.h" #include "x_platform.h" -#include <sys/shm.h> - -RedPixmapCairo::RedPixmapCairo(int width, int height, RedPixmap::Format format, +RedPixmapCairo::RedPixmapCairo(int width, int height, RedDrawable::Format format, bool top_bottom, RedWindow *win) : RedPixmap(width, height, format, top_bottom) { - ASSERT(format == RedPixmap::ARGB32 || format == RedPixmap::RGB32 || - format == RedPixmap::RGB16_555 || format == RedPixmap::RGB16_565 || - format == RedPixmap::A1); + ASSERT(format == RedDrawable::ARGB32 || format == RedDrawable::RGB32 || + format == RedDrawable::RGB16_555 || format == RedDrawable::RGB16_565 || + format == RedDrawable::A1); ASSERT(sizeof(RedDrawable_p) <= PIXELES_SOURCE_OPAQUE_SIZE); pixman_image_t *pixman_image; - XImage *image = NULL; - XShmSegmentInfo *shminfo = NULL; + XImage *image; + XShmSegmentInfo *shminfo; _data = NULL; - XVisualInfo *vinfo = NULL; - bool using_shm = false; - - - try { - pixman_format_code_t pixman_format; - - if (win) { - vinfo = XPlatform::get_vinfo()[win->get_screen_num()]; - } - - using_shm = vinfo && XPlatform::is_x_shm_avail(); - - if (using_shm) { - int depth = RedPixmap::format_to_bpp(format); - pixman_format = RedPixmap::format_to_pixman(format); - - shminfo = new XShmSegmentInfo; - shminfo->shmid = -1; - shminfo->shmaddr = 0; - ((PixelsSource_p*)get_opaque())->type = PIXELS_SOURCE_TYPE_XSHM_DRAWABLE; - memset(shminfo, 0, sizeof(XShmSegmentInfo)); - image = XShmCreateImage(XPlatform::get_display(), vinfo->visual, - depth, ZPixmap, NULL, shminfo, width, height); - if (!image) { - THROW("XShmCreateImage failed"); - } - - shminfo->shmid = shmget(IPC_PRIVATE, height * _stride, IPC_CREAT | 0777); - if (shminfo->shmid < 0) { - THROW("shmget failed"); - } - shminfo->shmaddr = (char *)shmat(shminfo->shmid, 0, 0); - if (shmctl(shminfo->shmid, IPC_RMID, NULL) == -1) { - LOG_WARN("shmctl IPC_RMID failed %s (%d)", strerror(errno), errno); - } - if (!shminfo->shmaddr) { - THROW("shmat failed"); - } - shminfo->readOnly = False; - if (!XShmAttach(XPlatform::get_display(), shminfo)) { - THROW("XShmAttach failed"); - } - - ((PixelsSource_p*)get_opaque())->x_shm_drawable.x_image = image; - ((PixelsSource_p*)get_opaque())->x_shm_drawable.shminfo = shminfo; - _data = (uint8_t *)shminfo->shmaddr; - image->data = (char *)_data; - } else { - image = new XImage; - _data = new uint8_t[height * _stride]; - ((PixelsSource_p*)get_opaque())->type = PIXELS_SOURCE_TYPE_PIXMAP; - ((PixelsSource_p*)get_opaque())->pixmap.x_image = image; - memset(image, 0, sizeof(*image)); - image->width = _width; - image->height = _height; - - image->data = (char*)_data; - image->byte_order = LSBFirst; - image->bitmap_unit = 32; - image->bitmap_bit_order = LSBFirst; - image->bitmap_pad = 32; - - image->bytes_per_line = _stride; - switch (format) { - case RedPixmap::ARGB32: - case RedPixmap::RGB32: - image->depth = XPlatform::get_vinfo()[0]->depth; - image->format = ZPixmap; - image->bits_per_pixel = 32; - image->red_mask = 0x00ff0000; - image->green_mask = 0x0000ff00; - image->blue_mask = 0x000000ff; - pixman_format = format == RedPixmap::ARGB32 ? PIXMAN_a8r8g8b8 : - PIXMAN_x8r8g8b8; - break; - case RedPixmap::A1: - image->depth = 1; - image->format = XYBitmap; - pixman_format = PIXMAN_a1; - break; - default: - THROW("unsupported format %d", format); - } - - if (!XInitImage(image)) { - THROW("init image failed"); - } - } - pixman_image = pixman_image_create_bits(pixman_format, _width, _height, - (uint32_t *)_data, _stride); - if (pixman_image == NULL) { - THROW("surf create failed"); - } + XVisualInfo *vinfo; + int screen_num; + RedDrawable::Format screen_format; + + screen_num = win ? win->get_screen_num() : 0; + vinfo = XPlatform::get_vinfo()[screen_num]; + screen_format = XPlatform::get_screen_format(screen_num); + + image = NULL; + shminfo = NULL; + + /* Only create XImage if same format as screen (needs re-verifying at + draw time!) */ + if (RedDrawable::format_copy_compatible(format, screen_format) || + format == A1) { + image = XPlatform::create_x_image(format, width, height, + vinfo->depth, vinfo->visual, + &shminfo); + _stride = image->bytes_per_line; + _data = (uint8_t *)image->data; + } else { + _data = new uint8_t[height * _stride]; + } - if (!using_shm) { - ((PixelsSource_p*)get_opaque())->pixmap.pixman_image = pixman_image; - } else { - ((PixelsSource_p*)get_opaque())->x_shm_drawable.pixman_image = pixman_image; - } - } catch (...) { - if (using_shm) { - if (image) { - XDestroyImage(image); - } - if (shminfo) { - if (shminfo->shmid >= 0) { - shmctl(shminfo->shmid, IPC_RMID, NULL); - } - if (shminfo->shmaddr) { - shmdt(shminfo->shmaddr); - } - } - } else { - delete image; - delete _data; - } - throw; + pixman_image = pixman_image_create_bits(RedDrawable::format_to_pixman(format), + _width, _height, + (uint32_t *)_data, _stride); + if (pixman_image == NULL) { + THROW("surf create failed"); } + + ((PixelsSource_p*)get_opaque())->type = PIXELS_SOURCE_TYPE_PIXMAP; + ((PixelsSource_p*)get_opaque())->pixmap.shminfo = shminfo; + ((PixelsSource_p*)get_opaque())->pixmap.x_image = image; + ((PixelsSource_p*)get_opaque())->pixmap.pixman_image = pixman_image; + ((PixelsSource_p*)get_opaque())->pixmap.format = format; } RedPixmapCairo::~RedPixmapCairo() { - if (((PixelsSource_p*)get_opaque())->type == PIXELS_SOURCE_TYPE_PIXMAP) { - pixman_image_unref(((PixelsSource_p*)get_opaque())->pixmap.pixman_image); - delete ((PixelsSource_p*)get_opaque())->pixmap.x_image; - delete[] _data; + ASSERT(((PixelsSource_p*)get_opaque())->type == PIXELS_SOURCE_TYPE_PIXMAP); + + XShmSegmentInfo *shminfo = ((PixelsSource_p*)get_opaque())->pixmap.shminfo; + XImage *image = ((PixelsSource_p*)get_opaque())->pixmap.x_image; + + pixman_image_unref(((PixelsSource_p*)get_opaque())->pixmap.pixman_image); + + if (image) { + XPlatform::free_x_image(image, shminfo); } else { - pixman_image_unref(((PixelsSource_p*)get_opaque())->x_shm_drawable.pixman_image); - XShmSegmentInfo *shminfo = ((PixelsSource_p*)get_opaque())->x_shm_drawable.shminfo; - XShmDetach(XPlatform::get_display(), shminfo); - XDestroyImage(((PixelsSource_p*)get_opaque())->x_shm_drawable.x_image); - XSync(XPlatform::get_display(), False); - shmdt(shminfo->shmaddr); - delete shminfo; + delete[] _data; } } diff --git a/client/x11/red_window.cpp b/client/x11/red_window.cpp index 21567275..c9a16ec1 100644 --- a/client/x11/red_window.cpp +++ b/client/x11/red_window.cpp @@ -1164,6 +1164,7 @@ void RedWindow_p::create(RedWindow& red_window, PixelsSource_p& pix_source, int _expect_parent = false; pix_source.type = PIXELS_SOURCE_TYPE_X_DRAWABLE; pix_source.x_drawable.drawable = window; + pix_source.x_drawable.screen = _screen; pix_source.x_drawable.gc = gc; set_minmax(pix_source, width, height); sync(); |