mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-26 22:48:19 +00:00
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.
This commit is contained in:
parent
d2a2f18b6e
commit
774e5bd36f
@ -112,7 +112,7 @@ void UnsupportedCursor::draw(RedDrawable& dest, int x, int y, const SpiceRect& a
|
||||
|
||||
AlphaCursor::AlphaCursor(const SpiceCursorHeader& header, const uint8_t* data)
|
||||
: _pixmap (new RedPixmapCairo(header.width, header.height,
|
||||
RedPixmap::ARGB32, true, NULL))
|
||||
RedDrawable::ARGB32, true, NULL))
|
||||
{
|
||||
int stride = _pixmap->get_stride();
|
||||
uint8_t* dest = _pixmap->get_data();
|
||||
@ -131,7 +131,7 @@ MonoCursor::MonoCursor(const SpiceCursorHeader& header, const uint8_t* data)
|
||||
: _pixmap (NULL)
|
||||
, _height (header.height)
|
||||
{
|
||||
_pixmap.reset(new RedPixmapCairo(header.width, _height * 2, RedPixmap::A1,
|
||||
_pixmap.reset(new RedPixmapCairo(header.width, _height * 2, RedDrawable::A1,
|
||||
true, NULL));
|
||||
|
||||
int dest_stride = _pixmap->get_stride();
|
||||
@ -176,10 +176,10 @@ private:
|
||||
|
||||
ColorCursor::ColorCursor(const SpiceCursorHeader& header)
|
||||
: _pixmap (new RedPixmapCairo(header.width, header.height,
|
||||
RedPixmap::ARGB32, true, NULL))
|
||||
RedDrawable::ARGB32, true, NULL))
|
||||
, _invers (NULL)
|
||||
{
|
||||
_invers.reset(new RedPixmapCairo(header.width, header.height, RedPixmap::A1,
|
||||
_invers.reset(new RedPixmapCairo(header.width, header.height, RedDrawable::A1,
|
||||
true, NULL));
|
||||
}
|
||||
|
||||
|
||||
@ -888,7 +888,7 @@ GUI::GUI(Application& app, Application::State state)
|
||||
: ScreenLayer (SCREEN_LAYER_GUI, false)
|
||||
, _app (app)
|
||||
, _state (state)
|
||||
, _pixmap (new RedPixmapCairo(MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT, RedDrawable::RGB32, true, NULL))
|
||||
, _pixmap (new RedPixmapCairo(MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT, RedDrawable::RGB32, true, 0))
|
||||
, _renderer (new CEGUI::SoftRenderer(_pixmap->get_data(), MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT,
|
||||
_pixmap->get_stride()))
|
||||
, _gui_system (new CEGUI::System(_renderer, new CEGUIResourceProvider()))
|
||||
|
||||
@ -34,7 +34,7 @@ CCanvas::CCanvas(bool onscreen,
|
||||
{
|
||||
if (onscreen) {
|
||||
_pixmap = new RedPixmapCairo(width, height,
|
||||
RedPixmap::format_from_surface(format),
|
||||
RedDrawable::format_from_surface(format),
|
||||
true, win);
|
||||
_canvas = canvas_create_for_data(width, height, format,
|
||||
_pixmap->get_data(),
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
class RedPixmapCairo: public RedPixmap {
|
||||
public:
|
||||
RedPixmapCairo(int width, int height, Format format, bool top_bottom, RedWindow *win);
|
||||
RedPixmapCairo(int width, int height, Format format, bool top_bottom, RedWindow *window);
|
||||
~RedPixmapCairo();
|
||||
};
|
||||
|
||||
|
||||
@ -172,7 +172,7 @@ void RedScreen::create_composit_area()
|
||||
{
|
||||
destroy_composit_area();
|
||||
_composit_area = new RedPixmapCairo(_size.x, _size.y, _window.get_format(),
|
||||
false, -1);
|
||||
false, &_window);
|
||||
}
|
||||
|
||||
void RedScreen::adjust_window_rect(int x, int y)
|
||||
|
||||
@ -29,7 +29,7 @@ struct RedPixmap_p {
|
||||
HBITMAP prev_bitmap;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
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);
|
||||
|
||||
try {
|
||||
pixman_format_code_t pixman_format;
|
||||
image = NULL;
|
||||
shminfo = NULL;
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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;
|
||||
/* 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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user