summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2010-04-19 16:31:45 +0200
committerAlexander Larsson <alexl@redhat.com>2010-04-23 16:41:42 +0200
commit4f5a09a73d4659e6aaf6537bf9c582df7fe39f00 (patch)
tree611f839c79fffc4583ebd27199d2f7695718777b
parent774e5bd36f4fc156dd744a455ff7ddda27441568 (diff)
downloadspice-4f5a09a73d4659e6aaf6537bf9c582df7fe39f00.tar.gz
spice-4f5a09a73d4659e6aaf6537bf9c582df7fe39f00.tar.xz
spice-4f5a09a73d4659e6aaf6537bf9c582df7fe39f00.zip
Make each surface its own depth/format
Surface creation now specifies the exact format, not only the bit depth of each surface which is used for rendering. Additionally we now actually store the surfaces in that format, instead of converting everything to 32bpp when drawing or e.g. handling palettes.
-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;