summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/canvas.h9
-rw-r--r--client/display_channel.cpp42
-rw-r--r--client/display_channel.h8
-rw-r--r--common/cairo_canvas.c52
-rw-r--r--common/canvas_base.c451
-rw-r--r--common/canvas_utils.c15
-rw-r--r--common/canvas_utils.h3
-rw-r--r--common/gl_canvas.c16
-rw-r--r--server/red_worker.c50
-rw-r--r--server/vd_interface.h2
10 files changed, 307 insertions, 341 deletions
diff --git a/client/canvas.h b/client/canvas.h
index 1dc2acb2..82badc49 100644
--- a/client/canvas.h
+++ b/client/canvas.h
@@ -342,9 +342,12 @@ public:
int width, int height, int gross_pixels,
int n_bytes_per_pixel, bool top_down)
{
- pixman_image_t *surface = alloc_lz_image_surface((LzDecodeUsrData *)opaque_usr_info,
- type, width, height, gross_pixels,
- top_down);
+ ASSERT(type == LZ_IMAGE_TYPE_RGB32 || type == LZ_IMAGE_TYPE_RGBA);
+
+ pixman_image_t *surface =
+ alloc_lz_image_surface((LzDecodeUsrData *)opaque_usr_info,
+ type == LZ_IMAGE_TYPE_RGBA ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
+ width, height, gross_pixels, top_down);
uint8_t *data = (uint8_t *)pixman_image_get_data(surface);
if (!top_down) {
data = data - (gross_pixels / height) * n_bytes_per_pixel * (height - 1);
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index acbf5da7..1a326cf9 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -45,11 +45,11 @@
class CreatePrimarySurfaceEvent: public SyncEvent {
public:
- CreatePrimarySurfaceEvent(DisplayChannel& channel, int width, int height, int depth)
+ CreatePrimarySurfaceEvent(DisplayChannel& channel, int width, int height, uint32_t format)
: _channel (channel)
, _width (width)
, _height (height)
- , _depth (depth)
+ , _format (format)
{
}
@@ -58,14 +58,14 @@ public:
Application* app = (Application*)events_loop.get_owner();
_channel.screen()->lock_size();
_channel.screen()->resize(_width, _height);
- _channel.create_canvas(0, app->get_canvas_types(), _width, _height, _depth);
+ _channel.create_canvas(0, app->get_canvas_types(), _width, _height, _format);
}
private:
DisplayChannel& _channel;
int _width;
int _height;
- int _depth;
+ uint32_t _format;
};
class DestroyPrimarySurfaceEvent: public SyncEvent {
@@ -86,19 +86,20 @@ private:
class CreateSurfaceEvent: public SyncEvent {
public:
- CreateSurfaceEvent(DisplayChannel& channel, int surface_id, int width, int height, int depth)
+ CreateSurfaceEvent(DisplayChannel& channel, int surface_id, int width, int height,
+ uint32_t format)
: _channel (channel)
, _surface_id (surface_id)
, _width (width)
, _height (height)
- , _depth (depth)
+ , _format (format)
{
}
virtual void do_response(AbstractProcessLoop& events_loop)
{
Application* app = (Application*)events_loop.get_owner();
- _channel.create_canvas(_surface_id, app->get_canvas_types(), _width, _height, _depth);
+ _channel.create_canvas(_surface_id, app->get_canvas_types(), _width, _height, _format);
}
private:
@@ -106,7 +107,7 @@ private:
int _surface_id;
int _width;
int _height;
- int _depth;
+ uint32_t _format;
};
class DestroySurfaceEvent: public SyncEvent {
@@ -562,7 +563,7 @@ void DisplaySurfacesManger::del_canvas(int surface_id)
}
CSurfaces& DisplaySurfacesManger::get_surfaces()
-{
+{
return surfaces;
}
@@ -753,7 +754,7 @@ void DisplayChannel::recreate_ogl_context_interrupt()
delete canvas;
}
- if (!create_ogl_canvas(0, _x_res, _y_res, _depth, 0, _rendertype)) {
+ if (!create_ogl_canvas(0, _x_res, _y_res, _format, 0, _rendertype)) {
THROW("create_ogl_canvas failed");
}
@@ -1187,23 +1188,23 @@ void DisplayChannel::create_canvas(int surface_id, const std::vector<int>& canva
for (i = 0; i < canvas_types.size(); i++) {
- if (canvas_types[i] == CANVAS_OPTION_CAIRO && create_cairo_canvas(surface_id, width, height, depth)) {
+ if (canvas_types[i] == CANVAS_OPTION_CAIRO && create_cairo_canvas(surface_id, width, height, format)) {
break;
}
#ifdef USE_OGL
- if (canvas_types[i] == CANVAS_OPTION_OGL_FBO && create_ogl_canvas(surface_id, width, height, depth,
+ if (canvas_types[i] == CANVAS_OPTION_OGL_FBO && create_ogl_canvas(surface_id, width, height, format,
recreate,
RENDER_TYPE_FBO)) {
break;
}
- if (canvas_types[i] == CANVAS_OPTION_OGL_PBUFF && create_ogl_canvas(surface_id, width, height, depth,
+ if (canvas_types[i] == CANVAS_OPTION_OGL_PBUFF && create_ogl_canvas(surface_id, width, height, format,
recreate,
RENDER_TYPE_PBUFF)) {
break;
}
#endif
#ifdef WIN32
- if (canvas_types[i] == CANVAS_OPTION_GDI && create_gdi_canvas(surface_id, width, height, depth)) {
+ if (canvas_types[i] == CANVAS_OPTION_GDI && create_gdi_canvas(surface_id, width, height, format)) {
break;
}
#endif
@@ -1424,7 +1425,7 @@ void DisplayChannel::create_primary_surface(int width, int height, uint32_t form
clear_area();
AutoRef<CreatePrimarySurfaceEvent> event(new CreatePrimarySurfaceEvent(*this, width, height,
- depth));
+ format));
get_client().push_event(*event);
(*event)->wait();
if (!(*event)->success()) {
@@ -1433,7 +1434,7 @@ void DisplayChannel::create_primary_surface(int width, int height, uint32_t form
_x_res = width;
_y_res = height;
- _depth = depth;
+ _format = format;
canvas = surfaces_mngr.get_canvas(0);
@@ -1446,12 +1447,12 @@ void DisplayChannel::create_primary_surface(int width, int height, uint32_t form
#endif
}
-void DisplayChannel::create_surface(int surface_id, int width, int height, int depth)
+void DisplayChannel::create_surface(int surface_id, int width, int height, uint32_t format)
{
Canvas *canvas;
AutoRef<CreateSurfaceEvent> event(new CreateSurfaceEvent(*this, surface_id, width, height,
- depth));
+ format));
get_client().push_event(*event);
(*event)->wait();
if (!(*event)->success()) {
@@ -1508,10 +1509,11 @@ void DisplayChannel::handle_surface_create(RedPeer::InMessage* message)
{
SpiceMsgSurfaceCreate* surface_create = (SpiceMsgSurfaceCreate*)message->data();
if (surface_create->flags == SPICE_SURFACE_FLAGS_PRIMARY) {
- create_primary_surface(surface_create->width, surface_create->height, surface_create->depth);
+ create_primary_surface(surface_create->width, surface_create->height,
+ surface_create->format);
} else {
create_surface(surface_create->surface_id, surface_create->width, surface_create->height,
- surface_create->depth);
+ surface_create->format);
}
}
diff --git a/client/display_channel.h b/client/display_channel.h
index a5761b35..e864bfc8 100644
--- a/client/display_channel.h
+++ b/client/display_channel.h
@@ -143,12 +143,12 @@ private:
#endif
void destroy_canvas(int surface_id);
void create_canvas(int surface_id, const std::vector<int>& canvas_type, int width, int height,
- int depth);
+ uint32_t format);
void destroy_strams();
void update_cursor();
- void create_primary_surface(int width, int height, int depth);
- void create_surface(int surface_id, int width, int height, int depth);
+ void create_primary_surface(int width, int height, uint32_t format);
+ void create_surface(int surface_id, int width, int height, uint32_t format);
void destroy_primary_surface();
void destroy_surface(int surface_id);
@@ -199,7 +199,7 @@ private:
bool _mark;
int _x_res;
int _y_res;
- int _depth;
+ uint32_t _format;
#ifdef USE_OGL
RenderType _rendertype;
#endif
diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index fde43d7f..931fd36b 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -51,7 +51,7 @@ static pixman_image_t *canvas_get_pixman_brush(CairoCanvas *canvas,
return pixman_image_create_solid_fill(&c);
}
- case SPICE_BRUSH_TYPE_PATTERN: {
+ case SPICE_BRUSH_TYPE_PATTERN: {
CairoCanvas *surface_canvas;
pixman_image_t* surface;
pixman_transform_t t;
@@ -61,7 +61,7 @@ static pixman_image_t *canvas_get_pixman_brush(CairoCanvas *canvas,
surface = surface_canvas->image;
surface = pixman_image_ref(surface);
} else {
- surface = canvas_get_image(&canvas->base, brush->u.pattern.pat);
+ surface = canvas_get_image(&canvas->base, brush->u.pattern.pat, FALSE);
}
pixman_transform_init_translate(&t,
pixman_int_to_fixed(-brush->u.pattern.pos.x),
@@ -156,33 +156,6 @@ static void copy_region(SpiceCanvas *spice_canvas,
}
}
-static inline uint8_t get_converted_color(uint8_t color)
-{
- uint8_t msb;
-
- msb = color & 0xE0;
- msb = msb >> 5;
- color |= msb;
- return color;
-}
-
-static inline uint32_t get_color(CairoCanvas *canvas, uint32_t color)
-{
- int shift = canvas->base.color_shift == 8 ? 0 : 3;
- uint32_t ret;
-
- if (!shift) {
- return color;
- }
-
- ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
- ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
- ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
-
- return ret;
-}
-
-
static void fill_solid_spans(SpiceCanvas *spice_canvas,
SpicePoint *points,
int *widths,
@@ -197,7 +170,7 @@ static void fill_solid_spans(SpiceCanvas *spice_canvas,
points[i].x, points[i].y,
widths[i],
1,
- get_color(canvas, color));
+ color);
}
}
@@ -214,7 +187,7 @@ static void fill_solid_rects(SpiceCanvas *spice_canvas,
rects[i].x1, rects[i].y1,
rects[i].x2 - rects[i].x1,
rects[i].y2 - rects[i].y1,
- get_color(canvas, color));
+ color);
}
}
@@ -232,7 +205,7 @@ static void fill_solid_rects_rop(SpiceCanvas *spice_canvas,
rects[i].x1, rects[i].y1,
rects[i].x2 - rects[i].x1,
rects[i].y2 - rects[i].y1,
- get_color(canvas, color), rop);
+ color, rop);
}
}
@@ -504,7 +477,7 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas,
sx = (double)(src_width) / (dest_width);
sy = (double)(src_height) / (dest_height);
- scaled = pixman_image_create_bits(PIXMAN_x8r8g8b8,
+ scaled = pixman_image_create_bits(spice_pixman_image_get_format(src),
dest_width,
dest_height,
NULL, 0);
@@ -802,7 +775,7 @@ static void __colorkey_scale_image(SpiceCanvas *spice_canvas,
sx = (double)(src_width) / (dest_width);
sy = (double)(src_height) / (dest_height);
- scaled = pixman_image_create_bits(PIXMAN_x8r8g8b8,
+ scaled = pixman_image_create_bits(spice_pixman_image_get_format (src),
dest_width,
dest_height,
NULL, 0);
@@ -1026,16 +999,20 @@ static void canvas_read_bits(SpiceCanvas *spice_canvas, uint8_t *dest, int dest_
uint8_t *src;
int src_stride;
uint8_t *dest_end;
+ int bpp;
ASSERT(canvas && area);
surface = canvas->image;
+
+ bpp = spice_pixman_image_get_bpp(surface) / 8;
+
src_stride = pixman_image_get_stride(surface);
src = (uint8_t *)pixman_image_get_data(surface) +
- area->top * src_stride + area->left * sizeof(uint32_t);
+ area->top * src_stride + area->left * bpp;
dest_end = dest + (area->bottom - area->top) * dest_stride;
for (; dest != dest_end; dest += dest_stride, src += src_stride) {
- memcpy(dest, src, dest_stride);
+ memcpy(dest, src, (area->right - area->left) * bpp);
}
}
@@ -1095,6 +1072,9 @@ static SpiceCanvas *canvas_create_common(pixman_image_t *image,
if (need_init) {
return NULL;
}
+ spice_pixman_image_set_format(image,
+ spice_surface_format_to_pixman (format));
+
canvas = spice_new0(CairoCanvas, 1);
init_ok = canvas_base_init(&canvas->base, &cairo_canvas_ops,
pixman_image_get_width (image),
diff --git a/common/canvas_base.c b/common/canvas_base.c
index fb101fda..799722cd 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -109,6 +109,21 @@ static inline double fix_to_double(SPICE_FIXED28_4 fixed)
return (double)(fixed & 0x0f) / 0x0f + (fixed >> 4);
}
+static inline uint16_t rgb_32_to_16_555(uint32_t color)
+{
+ return
+ (((color) >> 3) & 0x001f) |
+ (((color) >> 6) & 0x03e0) |
+ (((color) >> 9) & 0x7c00);
+}
+static inline uint16_t rgb_32_to_16_565(uint32_t color)
+{
+ return
+ (((color) >> 3) & 0x001f) |
+ (((color) >> 5) & 0x07e0) |
+ (((color) >> 8) & 0xf800);
+}
+
static inline uint32_t canvas_16bpp_to_32bpp(uint32_t color)
{
uint32_t ret;
@@ -119,17 +134,6 @@ static inline uint32_t canvas_16bpp_to_32bpp(uint32_t color)
return ret;
}
-
-static inline int test_bit(void* addr, int bit)
-{
- return !!(((uint32_t*)addr)[bit >> 5] & (1 << (bit & 0x1f)));
-}
-
-static inline int test_bit_be(void* addr, int bit)
-{
- return !!(((uint8_t*)addr)[bit >> 3] & (0x80 >> (bit & 0x07)));
-}
-
#ifdef WIN32
static HDC create_compatible_dc()
{
@@ -396,31 +400,43 @@ static SpiceROP ropd_descriptor_to_rop(int desc,
return SPICE_ROP_COPY;
}
-static inline void canvas_localize_palette(CanvasBase *canvas, SpicePalette *palette)
+//#define DEBUG_DUMP_COMPRESS
+#ifdef DEBUG_DUMP_COMPRESS
+static void dump_surface(pixman_image_t *surface, int cache);
+#endif
+
+
+static pixman_format_code_t canvas_get_target_format(CanvasBase *canvas,
+ int source_has_alpha)
{
- if (canvas->color_shift == 5) {
- uint32_t *now = palette->ents;
- uint32_t *end = now + palette->num_ents;
- for (; now < end; now++) {
- *now = canvas_16bpp_to_32bpp(*now);
+ pixman_format_code_t format;
+
+ /* Convert to target surface format */
+ format = spice_surface_format_to_pixman (canvas->format);
+
+ if (!source_has_alpha) {
+ /* If the source doesn't have alpha, but the destination has,
+ don't convert to alpha, since that would fill the alpha bytes
+ with 0xff which is not expected if we just use the raw bits */
+ if (format == PIXMAN_a8r8g8b8) {
+ format = PIXMAN_x8r8g8b8;
}
}
+
+ return format;
}
-//#define DEBUG_DUMP_COMPRESS
-#ifdef DEBUG_DUMP_COMPRESS
-static void dump_surface(pixman_image_t *surface, int cache);
-#endif
-static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image, int invers)
+static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image,
+ int invers, int want_original)
{
pixman_image_t *surface = NULL;
QuicData *quic_data = &canvas->quic_data;
- QuicImageType type;
+ QuicImageType type, as_type;
+ pixman_format_code_t pixman_format;
uint8_t *dest;
int stride;
int width;
int height;
- int alpha;
#ifndef CAIRO_CANVAS_NO_CHUNKS
DataChunk **tmp;
DataChunk *chunk;
@@ -446,14 +462,26 @@ static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image
}
#endif
- switch (type) {
+ switch (type) {
case QUIC_IMAGE_TYPE_RGBA:
- alpha = 1;
+ as_type = QUIC_IMAGE_TYPE_RGBA;
+ pixman_format = PIXMAN_a8r8g8b8;
break;
case QUIC_IMAGE_TYPE_RGB32:
case QUIC_IMAGE_TYPE_RGB24:
+ as_type = QUIC_IMAGE_TYPE_RGB32;
+ pixman_format = PIXMAN_x8r8g8b8;
+ break;
case QUIC_IMAGE_TYPE_RGB16:
- alpha = 0;
+ if (!want_original &&
+ (canvas->format == SPICE_SURFACE_FMT_32_xRGB ||
+ canvas->format == SPICE_SURFACE_FMT_32_ARGB)) {
+ as_type = QUIC_IMAGE_TYPE_RGB32;
+ pixman_format = PIXMAN_x8r8g8b8;
+ } else {
+ as_type = QUIC_IMAGE_TYPE_RGB16;
+ pixman_format = PIXMAN_x1r5g5b5;
+ }
break;
case QUIC_IMAGE_TYPE_INVALID:
case QUIC_IMAGE_TYPE_GRAY:
@@ -468,7 +496,7 @@ static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image
#ifdef WIN32
canvas->dc,
#endif
- alpha ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
+ pixman_format,
width, height, FALSE);
if (surface == NULL) {
@@ -477,7 +505,7 @@ static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image
dest = (uint8_t *)pixman_image_get_data(surface);
stride = pixman_image_get_stride(surface);
- if (quic_decode(quic_data->quic, alpha ? QUIC_IMAGE_TYPE_RGBA : QUIC_IMAGE_TYPE_RGB32,
+ if (quic_decode(quic_data->quic, as_type,
dest, stride) == QUIC_ERROR) {
pixman_image_unref(surface);
CANVAS_ERROR("quic decode failed");
@@ -492,7 +520,7 @@ static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image
pix = (uint32_t *)dest;
end_pix = pix + width;
for (; pix < end_pix; pix++) {
- *pix ^= 0x00ffffff;
+ *pix ^= 0xffffffff;
}
}
}
@@ -503,170 +531,45 @@ static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image
return surface;
}
-static inline void canvas_copy_32bpp(uint8_t* dest, int dest_stride, uint8_t* src, int src_stride,
- int width, uint8_t* end)
-{
- for (; src != end; src += src_stride, dest += dest_stride) {
- memcpy(dest, src, width << 2);
- }
-}
-
-static inline void canvas_copy_24bpp(uint8_t* dest, int dest_stride, uint8_t* src, int src_stride,
- int width, uint8_t* end)
-{
- for (; src != end; src += src_stride, dest += dest_stride) {
- uint8_t* src_line = src;
- uint8_t* src_line_end = src_line + width * 3;
- uint8_t* dest_line = dest;
-
- for (; src_line < src_line_end; ++dest_line) {
- *(dest_line++) = *(src_line++);
- *(dest_line++) = *(src_line++);
- *(dest_line++) = *(src_line++);
- }
- }
-}
-
-static inline void canvas_copy_16bpp(uint8_t* dest, int dest_stride, uint8_t* src, int src_stride,
- int width, uint8_t* end)
-{
- for (; src != end; src += src_stride, dest += dest_stride) {
- uint16_t* src_line = (uint16_t*)src;
- uint16_t* src_line_end = src_line + width;
- uint32_t* dest_line = (uint32_t*)dest;
-
- for (; src_line < src_line_end; ++dest_line, src_line++) {
- *dest_line = canvas_16bpp_to_32bpp(*src_line);
- }
- }
-}
-
-static inline void canvas_copy_8bpp(uint8_t *dest, int dest_stride, uint8_t *src, int src_stride,
- int width, uint8_t *end, SpicePalette *palette)
-{
- if (!palette) {
- CANVAS_ERROR("no palette");
- }
-
- for (; src != end; src += src_stride, dest += dest_stride) {
- uint32_t *dest_line = (uint32_t*)dest;
- uint8_t *src_line = src;
- uint8_t *src_line_end = src_line + width;
-
- while (src_line < src_line_end) {
- ASSERT(*src_line < palette->num_ents);
- *(dest_line++) = palette->ents[*(src_line++)];
- }
- }
-}
-
-static inline void canvas_copy_4bpp_be(uint8_t* dest, int dest_stride, uint8_t* src, int src_stride,
- int width, uint8_t* end, SpicePalette *palette)
-{
- if (!palette) {
- CANVAS_ERROR("no palette");
- }
-
- for (; src != end; src += src_stride, dest += dest_stride) {
- uint32_t *dest_line = (uint32_t *)dest;
- uint8_t *now = src;
- int i;
-
- for (i = 0; i < (width >> 1); i++) {
- ASSERT((*now & 0x0f) < palette->num_ents);
- ASSERT(((*now >> 4) & 0x0f) < palette->num_ents);
- *(dest_line++) = palette->ents[(*now >> 4) & 0x0f];
- *(dest_line++) = palette->ents[*(now++) & 0x0f];
- }
- if (width & 1) {
- *(dest_line) = palette->ents[(*src >> 4) & 0x0f];
- }
- }
-}
-
-static inline void canvas_copy_1bpp_be(uint8_t* dest, int dest_stride, uint8_t* src, int src_stride,
- int width, uint8_t* end, SpicePalette *palette)
-{
- uint32_t fore_color;
- uint32_t back_color;
-
- if (!palette) {
- CANVAS_ERROR("no palette");
- }
-
- fore_color = palette->ents[1];
- back_color = palette->ents[0];
-
- for (; src != end; src += src_stride, dest += dest_stride) {
- uint32_t* dest_line = (uint32_t*)dest;
- int i;
-
- for (i = 0; i < width; i++) {
- if (test_bit_be(src, i)) {
- *(dest_line++) = fore_color;
- } else {
- *(dest_line++) = back_color;
- }
- }
- }
-}
-
static pixman_image_t *canvas_bitmap_to_surface(CanvasBase *canvas, SpiceBitmap* bitmap,
- SpicePalette *palette)
+ SpicePalette *palette, int want_original)
{
- uint8_t* src = (uint8_t *)SPICE_GET_ADDRESS(bitmap->data);
+ uint8_t* src;
int src_stride;
- uint8_t* end;
- uint8_t* dest;
- int dest_stride;
- pixman_image_t* image;
+ pixman_image_t *image;
+ pixman_format_code_t format;
+ src = (uint8_t *)SPICE_GET_ADDRESS(bitmap->data);
src_stride = bitmap->stride;
- end = src + (bitmap->y * src_stride);
access_test(canvas, src, bitmap->y * src_stride);
+ if (want_original) {
+ format = spice_bitmap_format_to_pixman(bitmap->format, canvas->format);
+ } else {
+ format = canvas_get_target_format(canvas,
+ bitmap->format == SPICE_BITMAP_FMT_RGBA);
+ }
+
image = surface_create(
#ifdef WIN32
- canvas->dc,
+ canvas->dc,
#endif
- (bitmap->format == SPICE_BITMAP_FMT_RGBA) ? PIXMAN_a8r8g8b8 :
- PIXMAN_x8r8g8b8,
- bitmap->x, bitmap->y, FALSE);
+ format,
+ bitmap->x, bitmap->y, FALSE);
if (image == NULL) {
CANVAS_ERROR("create surface failed");
}
- dest = (uint8_t *)pixman_image_get_data(image);
- dest_stride = pixman_image_get_stride(image);
- if (!(bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
- ASSERT(bitmap->y > 0);
- dest += dest_stride * ((int)bitmap->y - 1);
- dest_stride = -dest_stride;
- }
- switch (bitmap->format) {
- case SPICE_BITMAP_FMT_32BIT:
- case SPICE_BITMAP_FMT_RGBA:
- canvas_copy_32bpp(dest, dest_stride, src, src_stride, bitmap->x, end);
- break;
- case SPICE_BITMAP_FMT_24BIT:
- canvas_copy_24bpp(dest, dest_stride, src, src_stride, bitmap->x, end);
- break;
- case SPICE_BITMAP_FMT_16BIT:
- canvas_copy_16bpp(dest, dest_stride, src, src_stride, bitmap->x, end);
- break;
- case SPICE_BITMAP_FMT_8BIT:
- canvas_copy_8bpp(dest, dest_stride, src, src_stride, bitmap->x, end, palette);
- break;
- case SPICE_BITMAP_FMT_4BIT_BE:
- canvas_copy_4bpp_be(dest, dest_stride, src, src_stride, bitmap->x, end, palette);
- break;
- case SPICE_BITMAP_FMT_1BIT_BE:
- canvas_copy_1bpp_be(dest, dest_stride, src, src_stride, bitmap->x, end, palette);
- break;
- }
+ spice_bitmap_convert_to_pixman(format, image,
+ bitmap->format,
+ bitmap->flags,
+ bitmap->x, bitmap->y,
+ src, bitmap->stride,
+ canvas->format, palette);
return image;
}
+
#ifdef CAIRO_CANVAS_CACHE
static inline SpicePalette *canvas_get_palett(CanvasBase *canvas, SPICE_ADDRESS base_palette, uint8_t flags)
@@ -682,25 +585,24 @@ static inline SpicePalette *canvas_get_palett(CanvasBase *canvas, SPICE_ADDRESS
palette = (SpicePalette *)SPICE_GET_ADDRESS(base_palette);
access_test(canvas, palette, sizeof(SpicePalette));
access_test(canvas, palette, sizeof(SpicePalette) + palette->num_ents * sizeof(uint32_t));
- canvas_localize_palette(canvas, palette);
canvas->palette_cache->ops->put(canvas->palette_cache, palette);
} else {
palette = (SpicePalette *)SPICE_GET_ADDRESS(base_palette);
- canvas_localize_palette(canvas, palette);
}
return palette;
}
-static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int invers)
+static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int invers,
+ int want_original)
{
LzData *lz_data = &canvas->lz_data;
uint8_t *comp_buf = NULL;
int comp_size;
uint8_t *decomp_buf = NULL;
uint8_t *src;
- LzImageType type;
+ pixman_format_code_t pixman_format;
+ LzImageType type, as_type;
SpicePalette *palette;
- int alpha;
int n_comp_pixels;
int width;
int height;
@@ -731,17 +633,29 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
switch (type) {
case LZ_IMAGE_TYPE_RGBA:
- alpha = 1;
+ as_type = LZ_IMAGE_TYPE_RGBA;
+ pixman_format = PIXMAN_a8r8g8b8;
break;
case LZ_IMAGE_TYPE_RGB32:
case LZ_IMAGE_TYPE_RGB24:
- case LZ_IMAGE_TYPE_RGB16:
case LZ_IMAGE_TYPE_PLT1_LE:
case LZ_IMAGE_TYPE_PLT1_BE:
case LZ_IMAGE_TYPE_PLT4_LE:
case LZ_IMAGE_TYPE_PLT4_BE:
case LZ_IMAGE_TYPE_PLT8:
- alpha = 0;
+ as_type = LZ_IMAGE_TYPE_RGB32;
+ pixman_format = PIXMAN_x8r8g8b8;
+ break;
+ case LZ_IMAGE_TYPE_RGB16:
+ if (!want_original &&
+ (canvas->format == SPICE_SURFACE_FMT_32_xRGB ||
+ canvas->format == SPICE_SURFACE_FMT_32_ARGB)) {
+ as_type = LZ_IMAGE_TYPE_RGB32;
+ pixman_format = PIXMAN_x8r8g8b8;
+ } else {
+ as_type = LZ_IMAGE_TYPE_RGB16;
+ pixman_format = PIXMAN_x1r5g5b5;
+ }
break;
default:
CANVAS_ERROR("unexpected LZ image type");
@@ -756,7 +670,7 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
#endif
- alloc_lz_image_surface(&lz_data->decode_data, alpha ? LZ_IMAGE_TYPE_RGBA : LZ_IMAGE_TYPE_RGB32,
+ alloc_lz_image_surface(&lz_data->decode_data, pixman_format,
width, height, n_comp_pixels, top_down);
src = (uint8_t *)pixman_image_get_data(lz_data->decode_data.out_surface);
@@ -769,7 +683,7 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
decomp_buf = src;
}
- lz_decode(lz_data->lz, alpha ? LZ_IMAGE_TYPE_RGBA : LZ_IMAGE_TYPE_RGB32, decomp_buf);
+ lz_decode(lz_data->lz, as_type, decomp_buf);
if (invers) {
uint8_t *line = src;
@@ -781,7 +695,7 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
pix = (uint32_t *)line;
end_pix = pix + width;
for (; pix < end_pix; pix++) {
- *pix ^= 0x00ffffff;
+ *pix ^= 0xffffffff;
}
}
}
@@ -791,7 +705,8 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
// don't handle plts since bitmaps with plt can be decoded globaly to RGB32 (because
// same byte sequence can be transformed to different RGB pixels by different plts)
-static pixman_image_t *canvas_get_glz(CanvasBase *canvas, LZImage *image)
+static pixman_image_t *canvas_get_glz(CanvasBase *canvas, LZImage *image,
+ int want_original)
{
ASSERT(image->descriptor.type == SPICE_IMAGE_TYPE_GLZ_RGB);
#ifdef WIN32
@@ -849,7 +764,8 @@ static void dump_bitmap(SpiceBitmap *bitmap, SpicePalette *palette)
#endif
-static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
+static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap,
+ int want_original)
{
pixman_image_t* surface;
SpicePalette *palette;
@@ -861,7 +777,7 @@ static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
}
#endif
- surface = canvas_bitmap_to_surface(canvas, bitmap, palette);
+ surface = canvas_bitmap_to_surface(canvas, bitmap, palette, want_original);
if (palette && (bitmap->flags & SPICE_BITMAP_FLAGS_PAL_FROM_CACHE)) {
canvas->palette_cache->ops->release(canvas->palette_cache, palette);
@@ -873,27 +789,16 @@ static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
#else
-static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
+static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap,
+ int want_original)
{
SpicePalette *palette;
if (!bitmap->palette) {
- return canvas_bitmap_to_surface(canvas, bitmap, NULL);
+ return canvas_bitmap_to_surface(canvas, bitmap, NULL, want_original);
}
palette = (SpicePalette *)SPICE_GET_ADDRESS(bitmap->palette);
- if (canvas->color_shift == 5) {
- int size = sizeof(SpicePalette) + (palette->num_ents << 2);
- SpicePalette *local_palette = spice_malloc(size);
- pixman_image_t* surface;
-
- memcpy(local_palette, palette, size);
- canvas_localize_palette(canvas, local_palette);
- surface = canvas_bitmap_to_surface(canvas, bitmap, local_palette);
- free(local_palette);
- return surface;
- } else {
- return canvas_bitmap_to_surface(canvas, bitmap, palette);
- }
+ return canvas_bitmap_to_surface(canvas, bitmap, palette, want_original);
}
#endif
@@ -984,11 +889,20 @@ static SpiceCanvas *canvas_get_surface_mask_internal(CanvasBase *canvas, SPICE_A
//#define DEBUG_LZ
/* If real get is FALSE, then only do whatever is needed but don't return an image. For instance,
- if we need to read it to cache it we do. */
-static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRESS addr, int real_get)
+ * if we need to read it to cache it we do.
+ *
+ * This generally converts the image to the right type for the canvas.
+ * However, if want_original is set the real source format is returned, and
+ * you have to be able to handle any image format. This is useful to avoid
+ * e.g. losing alpha when blending a argb32 image on a rgb16 surface.
+ */
+static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRESS addr,
+ int want_original, int real_get)
{
SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
- pixman_image_t *surface;
+ pixman_image_t *surface, *converted;
+ pixman_format_code_t wanted_format, surface_format;
+ int saved_want_original;
access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
#ifdef DEBUG_LZ
LOG_DEBUG("canvas_get_image image type: " << (int)descriptor->type);
@@ -1003,24 +917,29 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
return NULL;
}
+ saved_want_original = want_original;
+ if (descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_ME) {
+ want_original = TRUE;
+ }
+
switch (descriptor->type) {
case SPICE_IMAGE_TYPE_QUIC: {
SpiceQUICImage *image = (SpiceQUICImage *)descriptor;
access_test(canvas, descriptor, sizeof(SpiceQUICImage));
- surface = canvas_get_quic(canvas, image, 0);
+ surface = canvas_get_quic(canvas, image, 0, want_original);
break;
}
#ifdef CAIRO_CANVAS_NO_CHUNKS
case SPICE_IMAGE_TYPE_LZ_PLT: {
access_test(canvas, descriptor, sizeof(SpiceLZPLTImage));
LZImage *image = (LZImage *)descriptor;
- surface = canvas_get_lz(canvas, image, 0);
+ surface = canvas_get_lz(canvas, image, 0, want_original);
break;
}
case SPICE_IMAGE_TYPE_LZ_RGB: {
access_test(canvas, descriptor, sizeof(SpiceLZRGBImage));
LZImage *image = (LZImage *)descriptor;
- surface = canvas_get_lz(canvas, image, 0);
+ surface = canvas_get_lz(canvas, image, 0, want_original);
break;
}
#endif
@@ -1029,24 +948,27 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
case SPICE_IMAGE_TYPE_GLZ_RGB: {
access_test(canvas, descriptor, sizeof(SpiceLZRGBImage));
LZImage *image = (LZImage *)descriptor;
- surface = canvas_get_glz(canvas, image);
+ surface = canvas_get_glz(canvas, image, want_original);
break;
}
#endif
case SPICE_IMAGE_TYPE_FROM_CACHE:
- return canvas->bits_cache->ops->get(canvas->bits_cache, descriptor->id);
+ surface = canvas->bits_cache->ops->get(canvas->bits_cache, descriptor->id);
+ break;
+
case SPICE_IMAGE_TYPE_BITMAP: {
SpiceBitmapImage *bitmap = (SpiceBitmapImage *)descriptor;
access_test(canvas, descriptor, sizeof(SpiceBitmapImage));
- surface = canvas_get_bits(canvas, &bitmap->bitmap);
+ surface = canvas_get_bits(canvas, &bitmap->bitmap, want_original);
break;
}
default:
CANVAS_ERROR("invalid image type");
}
- if (descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_ME) {
+ if (descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_ME &&
+ descriptor->type != SPICE_IMAGE_TYPE_FROM_CACHE) {
canvas->bits_cache->ops->put(canvas->bits_cache, descriptor->id, surface);
#ifdef DEBUG_DUMP_SURFACE
dump_surface(surface, 1);
@@ -1062,14 +984,48 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
return NULL;
}
+ surface_format = spice_pixman_image_get_format(surface);
+
+ if (!saved_want_original) {
+ /* Conversion to canvas format was requested, but maybe it didn't
+ happen above (due to save/load to cache for instance, or
+ maybe the reader didn't support conversion).
+ If so we convert here. */
+
+ wanted_format = canvas_get_target_format(canvas,
+ surface_format == PIXMAN_a8r8g8b8);
+
+ if (surface_format != wanted_format) {
+ converted = surface_create(
+#ifdef WIN32
+ canvas->dc,
+#endif
+ wanted_format,
+ pixman_image_get_width(surface),
+ pixman_image_get_height(surface),
+ TRUE);
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ surface, NULL, converted,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ pixman_image_get_width(surface),
+ pixman_image_get_height(surface));
+ pixman_image_unref (surface);
+ surface = converted;
+ }
+ }
+
return surface;
}
#else
-static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRESS addr, int real_get)
+static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRESS addr,
+ int want_original, int real_get)
{
SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
+ pixman_format_code_t format;
access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
@@ -1087,7 +1043,7 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
case SPICE_IMAGE_TYPE_BITMAP: {
SpiceBitmapImage *bitmap = (SpiceBitmapImage *)descriptor;
access_test(canvas, descriptor, sizeof(SpiceBitmapImage));
- return canvas_get_bits(canvas, &bitmap->bitmap);
+ return canvas_get_bits(canvas, &bitmap->bitmap, want_original, &format);
}
default:
CANVAS_ERROR("invalid image type");
@@ -1106,26 +1062,29 @@ static SpiceCanvas *canvas_get_surface(CanvasBase *canvas, SPICE_ADDRESS addr)
return canvas_get_surface_internal(canvas, addr);
}
-static pixman_image_t *canvas_get_image(CanvasBase *canvas, SPICE_ADDRESS addr)
+static pixman_image_t *canvas_get_image(CanvasBase *canvas, SPICE_ADDRESS addr,
+ int want_original)
{
- return canvas_get_image_internal(canvas, addr, TRUE);
+ return canvas_get_image_internal(canvas, addr, want_original, TRUE);
}
static void canvas_touch_image(CanvasBase *canvas, SPICE_ADDRESS addr)
{
- canvas_get_image_internal(canvas, addr, FALSE);
+ canvas_get_image_internal(canvas, addr, TRUE, FALSE);
}
static pixman_image_t* canvas_get_image_from_self(SpiceCanvas *canvas,
int x, int y,
int32_t width, int32_t height)
{
+ CanvasBase *canvas_base = (CanvasBase *)canvas;
pixman_image_t *surface;
uint8_t *dest;
int dest_stride;
SpiceRect area;
- surface = pixman_image_create_bits(PIXMAN_x8r8g8b8, width, height, NULL, 0);
+ surface = pixman_image_create_bits(spice_surface_format_to_pixman (canvas_base->format),
+ width, height, NULL, 0);
if (surface == NULL) {
CANVAS_ERROR("create surface failed");
}
@@ -1569,7 +1528,8 @@ static pixman_image_t *canvas_scale_surface(pixman_image_t *src, const SpiceRect
pixman_transform_t transform;
double sx, sy;
- surface = pixman_image_create_bits(PIXMAN_x8r8g8b8, width, height, NULL, 0);
+ surface = pixman_image_create_bits(spice_pixman_image_get_format (src),
+ width, height, NULL, 0);
if (surface == NULL) {
CANVAS_ERROR("create surface failed");
}
@@ -1933,7 +1893,7 @@ static void draw_brush(SpiceCanvas *canvas,
rop);
}
} else {
- tile = canvas_get_image(canvas_base, pattern->pat);
+ tile = canvas_get_image(canvas_base, pattern->pat, FALSE);
if (rop == SPICE_ROP_COPY) {
canvas->ops->fill_tiled_rects(canvas, rects, n_rects, tile, offset_x, offset_y);
} else {
@@ -2067,7 +2027,7 @@ static void canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl
}
}
} else {
- src_image = canvas_get_image(canvas, copy->src_bitmap);
+ src_image = canvas_get_image(canvas, copy->src_bitmap, FALSE);
if (rect_is_same_size(bbox, &copy->src_area)) {
if (rop == SPICE_ROP_COPY) {
spice_canvas->ops->blit_image(spice_canvas, &dest_region,
@@ -2120,6 +2080,7 @@ static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox,
SpiceCanvas *surface_canvas;
pixman_image_t *src_image;
pixman_region32_t dest_region;
+ uint32_t transparent_color;
pixman_region32_init_rect(&dest_region,
bbox->left, bbox->top,
@@ -2134,6 +2095,19 @@ static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox,
return;
}
+ switch (canvas->format) {
+ case SPICE_SURFACE_FMT_32_xRGB:
+ case SPICE_SURFACE_FMT_32_ARGB:
+ transparent_color = transparent->true_color;
+ break;
+ case SPICE_SURFACE_FMT_16_555:
+ transparent_color = rgb_32_to_16_555(transparent->true_color);
+ break;
+ case SPICE_SURFACE_FMT_16_565:
+ transparent_color = rgb_32_to_16_565(transparent->true_color);
+ break;
+ }
+
surface_canvas = canvas_get_surface(canvas, transparent->src_bitmap);
if (surface_canvas) {
if (rect_is_same_size(bbox, &transparent->src_area)) {
@@ -2141,7 +2115,7 @@ static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox,
surface_canvas,
bbox->left - transparent->src_area.left,
bbox->top - transparent->src_area.top,
- transparent->true_color);
+ transparent_color);
} else {
spice_canvas->ops->colorkey_scale_image_from_surface(spice_canvas, &dest_region,
surface_canvas,
@@ -2153,16 +2127,16 @@ static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox,
bbox->top,
bbox->right - bbox->left,
bbox->bottom - bbox->top,
- transparent->true_color);
+ transparent_color);
}
} else {
- src_image = canvas_get_image(canvas, transparent->src_bitmap);
+ src_image = canvas_get_image(canvas, transparent->src_bitmap, FALSE);
if (rect_is_same_size(bbox, &transparent->src_area)) {
spice_canvas->ops->colorkey_image(spice_canvas, &dest_region,
src_image,
bbox->left - transparent->src_area.left,
bbox->top - transparent->src_area.top,
- transparent->true_color);
+ transparent_color);
} else {
spice_canvas->ops->colorkey_scale_image(spice_canvas, &dest_region,
src_image,
@@ -2174,7 +2148,7 @@ static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox,
bbox->top,
bbox->right - bbox->left,
bbox->bottom - bbox->top,
- transparent->true_color);
+ transparent_color);
}
pixman_image_unref(src_image);
}
@@ -2229,7 +2203,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
alpha_blend->alpha);
}
} else {
- src_image = canvas_get_image(canvas, alpha_blend->src_bitmap);
+ src_image = canvas_get_image(canvas, alpha_blend->src_bitmap, TRUE);
if (rect_is_same_size(bbox, &alpha_blend->src_area)) {
spice_canvas->ops->blend_image(spice_canvas, &dest_region,
src_image,
@@ -2288,7 +2262,7 @@ static void canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spice
return;
}
- src_image = canvas_get_image(canvas, opaque->src_bitmap);
+ src_image = canvas_get_image(canvas, opaque->src_bitmap, FALSE);
if (rect_is_same_size(bbox, &opaque->src_area)) {
spice_canvas->ops->blit_image(spice_canvas, &dest_region,
@@ -2389,7 +2363,7 @@ static void canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceC
}
}
} else {
- src_image = canvas_get_image(canvas, blend->src_bitmap);
+ src_image = canvas_get_image(canvas, blend->src_bitmap, FALSE);
if (rect_is_same_size(bbox, &blend->src_area)) {
if (rop == SPICE_ROP_COPY)
spice_canvas->ops->blit_image(spice_canvas, &dest_region,
@@ -2933,7 +2907,8 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox,
} else {
gc.use_surface_canvas = FALSE;
gc.tile = canvas_get_image(canvas,
- stroke->brush.u.pattern.pat);
+ stroke->brush.u.pattern.pat,
+ FALSE);
}
gc.tile_offset_x = stroke->brush.u.pattern.pos.x;
gc.tile_offset_y = stroke->brush.u.pattern.pos.y;
@@ -3034,7 +3009,7 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox,
if (surface_canvas) {
s = surface_canvas->ops->get_image(surface_canvas);
} else {
- s = canvas_get_image(canvas, rop3->src_bitmap);
+ s = canvas_get_image(canvas, rop3->src_bitmap, FALSE);
}
if (!rect_is_same_size(bbox, &rop3->src_area)) {
@@ -3060,7 +3035,7 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox,
if (_surface_canvas) {
p = _surface_canvas->ops->get_image(_surface_canvas);
} else {
- p = canvas_get_image(canvas, rop3->brush.u.pattern.pat);
+ p = canvas_get_image(canvas, rop3->brush.u.pattern.pat, FALSE);
}
SpicePoint pat_pos;
@@ -3069,9 +3044,7 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox,
do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos);
pixman_image_unref(p);
} else {
- uint32_t color = (canvas->color_shift) == 8 ? rop3->brush.u.color :
- canvas_16bpp_to_32bpp(rop3->brush.u.color);
- do_rop3_with_color(rop3->rop3, d, s, &src_pos, color);
+ do_rop3_with_color(rop3->rop3, d, s, &src_pos, rop3->brush.u.color);
}
pixman_image_unref(s);
diff --git a/common/canvas_utils.c b/common/canvas_utils.c
index 4f2456d6..1f6eca67 100644
--- a/common/canvas_utils.c
+++ b/common/canvas_utils.c
@@ -283,11 +283,11 @@ pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, in
return __surface_create_stride(format, width, height, stride);
}
-pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data, LzImageType type, int width,
+pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
+ pixman_format_code_t pixman_format, int width,
int height, int gross_pixels, int top_down)
{
int stride;
- int alpha;
pixman_image_t *surface = NULL;
stride = (gross_pixels / height) * 4;
@@ -296,18 +296,11 @@ pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data, LzImageType
stride = -stride;
}
- if (type == LZ_IMAGE_TYPE_RGB32) {
- alpha = 0;
- } else if (type == LZ_IMAGE_TYPE_RGBA) {
- alpha = 1;
- } else {
- CANVAS_ERROR("unexpected image type");
- }
- surface = surface_create_stride(
+ surface = surface_create_stride(
#ifdef WIN32
canvas_data->dc,
#endif
- alpha ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8, width, height, stride);
+ pixman_format, width, height, stride);
canvas_data->out_surface = surface;
return surface;
}
diff --git a/common/canvas_utils.h b/common/canvas_utils.h
index b81a6f91..b87b8164 100644
--- a/common/canvas_utils.h
+++ b/common/canvas_utils.h
@@ -62,6 +62,7 @@ typedef struct LzDecodeUsrData {
} LzDecodeUsrData;
-pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data, LzImageType type, int width,
+pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
+ pixman_format_code_t pixman_format, int width,
int height, int gross_pixels, int top_down);
#endif
diff --git a/common/gl_canvas.c b/common/gl_canvas.c
index 9b017fa2..63d69779 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -275,7 +275,7 @@ static void set_brush(GLCanvas *canvas, SpiceBrush *brush)
GLCPattern pattern;
pixman_image_t *surface;
- surface = canvas_get_image(&canvas->base, brush->u.pattern.pat);
+ surface = canvas_get_image(&canvas->base, brush->u.pattern.pat, FALSE);
surface_to_image(canvas, surface, &image, 0);
pattern = glc_pattern_create(canvas->glc, -brush->u.pattern.pos.x,
@@ -379,7 +379,7 @@ static void gl_canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spic
set_op(canvas, copy->rop_decriptor);
//todo: optimize get_imag (use ogl conversion + remove unnecessary copy of 32bpp)
- surface = canvas_get_image(&canvas->base, copy->src_bitmap);
+ surface = canvas_get_image(&canvas->base, copy->src_bitmap, FALSE);
surface_to_image(canvas, surface, &image, 0);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &copy->src_area);
@@ -403,7 +403,7 @@ static void gl_canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, Sp
glc_set_op(canvas->glc, (opaque->rop_decriptor & SPICE_ROPD_INVERS_SRC) ? GLC_OP_COPY_INVERTED :
GLC_OP_COPY);
- surface = canvas_get_image(&canvas->base, opaque->src_bitmap);
+ surface = canvas_get_image(&canvas->base, opaque->src_bitmap, FALSE);
surface_to_image(canvas, surface, &image, 0);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &opaque->src_area);
@@ -430,7 +430,7 @@ static void gl_canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbo
glc_clear_mask(canvas->glc, GLC_MASK_A);
glc_set_op(canvas->glc, GLC_OP_COPY);
- surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap);
+ surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap, FALSE);
surface_to_image(canvas, surface, &image, 0);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &alpha_blend->src_area);
@@ -452,7 +452,7 @@ static void gl_canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spi
set_mask(canvas, &blend->mask, bbox->left, bbox->top);
set_op(canvas, blend->rop_decriptor);
- surface = canvas_get_image(&canvas->base, blend->src_bitmap);
+ surface = canvas_get_image(&canvas->base, blend->src_bitmap, FALSE);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &blend->src_area);
surface_to_image(canvas, surface, &image, 0);
@@ -475,7 +475,7 @@ static void gl_canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbo
glc_clear_mask(canvas->glc, GLC_MASK_A);
glc_set_op(canvas->glc, GLC_OP_COPY);
- surface = canvas_get_image(&canvas->base, transparent->src_bitmap);
+ surface = canvas_get_image(&canvas->base, transparent->src_bitmap, FALSE);
surface_to_image(canvas, surface, &image, 0);
trans_surf = canvas_surf_to_trans_surf(&image, transparent->true_color);
@@ -554,7 +554,7 @@ static void gl_canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spic
memcpy(image.pixels, data_opp,
image.stride * pixman_image_get_height(d));
- s = canvas_get_image(&canvas->base, rop3->src_bitmap);
+ s = canvas_get_image(&canvas->base, rop3->src_bitmap, FALSE);
src_stride = pixman_image_get_stride(s);
if (src_stride > 0) {
data_opp = copy_opposite_image(canvas, (uint8_t *)pixman_image_get_data(s),
@@ -581,7 +581,7 @@ static void gl_canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spic
}
if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
- pixman_image_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat);
+ pixman_image_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat, FALSE);
SpicePoint pat_pos;
pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % pixman_image_get_width(p);
diff --git a/server/red_worker.c b/server/red_worker.c
index af3a8883..7d6df888 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -872,7 +872,7 @@ typedef struct DrawContext {
uint32_t width;
uint32_t height;
int32_t stride;
- uint8_t depth;
+ uint32_t format;
void *line_0;
} DrawContext;
@@ -3573,6 +3573,7 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
uint8_t *dest;
int dest_stride;
RedSurface *surface;
+ int bpp;
if (!drawable->qxl_drawable->self_bitmap) {
return TRUE;
@@ -3581,9 +3582,11 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
surface = &worker->surfaces[drawable->surface_id];
+ bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
+
width = drawable->qxl_drawable->bbox.right - drawable->qxl_drawable->bbox.left;
height = drawable->qxl_drawable->bbox.bottom - drawable->qxl_drawable->bbox.top;
- dest_stride = width * sizeof(uint32_t);
+ dest_stride = SPICE_ALIGN(width * bpp, 4);
image = spice_malloc_n_m(height, dest_stride, sizeof(QXLImage));
dest = (uint8_t *)(image + 1);
@@ -3594,7 +3597,19 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_RED, ++worker->bits_unique);
image->bitmap.flags = QXL_BITMAP_DIRECT | (surface->context.top_down ?
QXL_BITMAP_TOP_DOWN : 0);
- image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
+ switch (surface->context.format) {
+ case SPICE_SURFACE_FMT_32_xRGB:
+ image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
+ break;
+ case SPICE_SURFACE_FMT_32_ARGB:
+ image->bitmap.format = SPICE_BITMAP_FMT_RGBA;
+ break;
+ case SPICE_SURFACE_FMT_16_555:
+ image->bitmap.format = SPICE_BITMAP_FMT_16BIT;
+ break;
+ default:
+ ASSERT(0); /* not supported yet */
+ }
image->bitmap.stride = dest_stride;
image->descriptor.width = image->bitmap.x = width;
image->descriptor.height = image->bitmap.y = height;
@@ -3801,7 +3816,8 @@ static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable
}
static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uint32_t width,
- uint32_t height, int32_t stride, uint8_t depth, void *line_0);
+ uint32_t height, int32_t stride, uint32_t format,
+ void *line_0);
static inline void red_process_surface(RedWorker *worker, QXLSurfaceCmd *surface, uint32_t group_id)
{
@@ -3820,13 +3836,13 @@ static inline void red_process_surface(RedWorker *worker, QXLSurfaceCmd *surface
uint32_t height = surface->u.surface_create.height;
int32_t stride = surface->u.surface_create.stride;
QXLReleaseInfoExt release_info_ext;
-
+
data = (uint8_t *)get_virt(&worker->mem_slots, saved_data, height * abs(stride), group_id);
if (stride < 0) {
data -= (int32_t)(stride * (height - 1));
}
red_create_surface(worker, surface_id, surface->u.surface_create.width,
- height, stride, surface->u.surface_create.depth, data);
+ height, stride, surface->u.surface_create.format, data);
release_info_ext.group_id = group_id;
release_info_ext.info = &surface->release_info;
worker->qxl->release_resource(worker->qxl, release_info_ext);
@@ -7881,7 +7897,7 @@ static inline void *create_canvas_for_surface(RedWorker *worker, RedSurface *sur
}
static SurfaceCreateItem *get_surface_create_item(uint32_t surface_id, uint32_t width,
- uint32_t height, uint8_t depth, uint32_t flags)
+ uint32_t height, uint32_t format, uint32_t flags)
{
SurfaceCreateItem *create;
@@ -7892,7 +7908,7 @@ static SurfaceCreateItem *get_surface_create_item(uint32_t surface_id, uint32_t
create->surface_create.width = width;
create->surface_create.height = height;
create->surface_create.flags = flags;
- create->surface_create.depth = depth;
+ create->surface_create.format = format;
red_pipe_item_init(&create->pipe_item, PIPE_ITEM_TYPE_CREATE_SURFACE);
@@ -7911,7 +7927,7 @@ static inline void __red_create_surface_item(RedWorker *worker, int surface_id,
surface = &worker->surfaces[surface_id];
create = get_surface_create_item(surface_id, surface->context.width, surface->context.height,
- surface->context.depth, flags);
+ surface->context.format, flags);
worker->display_channel->surface_client_created[surface_id] = TRUE;
@@ -7924,26 +7940,24 @@ static inline void red_create_surface_item(RedWorker *worker, int surface_id)
__red_create_surface_item(worker, surface_id, SPICE_SURFACE_FLAGS_PRIMARY);
} else {
__red_create_surface_item(worker, surface_id, 0);
- }
+ }
}
static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, uint32_t width,
- uint32_t height, int32_t stride, uint8_t depth, void *line_0)
+ uint32_t height, int32_t stride, uint32_t format,
+ void *line_0)
{
uint32_t i;
RedSurface *surface = &worker->surfaces[surface_id];
if (stride >= 0) {
PANIC("Untested path stride >= 0");
}
- if (depth != 16 && depth != 32) {
- PANIC("As for now support just 32/16 depth surfaces");
- }
PANIC_ON(surface->context.canvas);
surface->context.canvas_draws_on_surface = FALSE;
surface->context.width = width;
surface->context.height = height;
- surface->context.depth = depth;
+ surface->context.format = format;
surface->context.stride = stride;
surface->context.line_0 = line_0;
memset(line_0 + (int32_t)(stride * (height - 1)), 0, height*abs(stride));
@@ -7957,7 +7971,7 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
if (worker->renderer != RED_RENDERER_INVALID) {
surface->context.canvas = create_canvas_for_surface(worker, surface, worker->renderer,
width, height, stride,
- surface->context.depth, line_0);
+ surface->context.format, line_0);
if (!surface->context.canvas) {
PANIC("drawing canvas creating failed - can`t create same type canvas");
}
@@ -7969,7 +7983,7 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
for (i = 0; i < worker->num_renderers; i++) {
surface->context.canvas = create_canvas_for_surface(worker, surface, worker->renderers[i],
width, height, stride,
- surface->context.depth, line_0);
+ surface->context.format, line_0);
if (surface->context.canvas) { //no need canvas check
worker->renderer = worker->renderers[i];
red_create_surface_item(worker, surface_id);
@@ -9043,7 +9057,7 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
line_0 -= (int32_t)(surface.stride * (surface.height -1));
}
- red_create_surface(worker, 0, surface.width, surface.height, surface.stride, surface.depth,
+ red_create_surface(worker, 0, surface.width, surface.height, surface.stride, surface.format,
line_0);
if (worker->display_channel) {
diff --git a/server/vd_interface.h b/server/vd_interface.h
index 25ff007e..e91539f1 100644
--- a/server/vd_interface.h
+++ b/server/vd_interface.h
@@ -173,7 +173,7 @@ struct QXLDevSurfaceCreate {
uint32_t width;
uint32_t height;
int32_t stride;
- uint32_t depth;
+ uint32_t format;
uint32_t position;
uint32_t mouse_mode;
uint32_t flags;