diff options
-rw-r--r-- | client/Makefile.am | 1 | ||||
-rw-r--r-- | client/pixman_utils.cpp | 25 | ||||
-rw-r--r-- | client/x11/Makefile.am | 1 | ||||
-rw-r--r-- | common/Makefile.am | 2 | ||||
-rw-r--r-- | common/pixman_utils.c | 938 | ||||
-rw-r--r-- | common/pixman_utils.h | 103 | ||||
-rw-r--r-- | server/Makefile.am | 1 |
7 files changed, 1071 insertions, 0 deletions
diff --git a/client/Makefile.am b/client/Makefile.am index b453e943..c59b6f31 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -10,6 +10,7 @@ RED_COMMON_SRCS = \ audio_devices.h \ cache.hpp \ cairo_canvas.cpp \ + pixman_utils.cpp \ canvas.cpp \ canvas.h \ canvas_utils.cpp \ diff --git a/client/pixman_utils.cpp b/client/pixman_utils.cpp new file mode 100644 index 00000000..337e07cb --- /dev/null +++ b/client/pixman_utils.cpp @@ -0,0 +1,25 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "utils.h" + + +#define CANVAS_ERROR(format, ...) THROW(format, ## __VA_ARGS__) + +#include "../common/pixman_utils.c" + diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am index c5efd861..e50c4ae6 100644 --- a/client/x11/Makefile.am +++ b/client/x11/Makefile.am @@ -71,6 +71,7 @@ RED_COMMON_SRCS = \ $(top_srcdir)/client/menu.cpp \ $(top_srcdir)/client/menu.h \ $(top_srcdir)/client/pixels_source.h \ + $(top_srcdir)/client/pixman_utils.cpp \ $(top_srcdir)/client/platform.h \ $(top_srcdir)/client/playback_channel.cpp \ $(top_srcdir)/client/process_loop.cpp \ diff --git a/common/Makefile.am b/common/Makefile.am index 7fcdfe90..2d184406 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -3,6 +3,8 @@ NULL = COMMON_SRCS = \ cairo_canvas.h \ cairo_canvas.c \ + pixman_utils.h \ + pixman_utils.c \ canvas_base.h \ canvas_base.c \ canvas_utils.h \ diff --git a/common/pixman_utils.c b/common/pixman_utils.c new file mode 100644 index 00000000..27257f7a --- /dev/null +++ b/common/pixman_utils.c @@ -0,0 +1,938 @@ +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ +/* + Copyright (C) 2009 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "pixman_utils.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#ifndef FALSE +# define FALSE 0 +#endif + +#ifndef TRUE +# define TRUE 1 +#endif + +#ifndef ASSERT +#define ASSERT(x) if (!(x)) { \ + printf("%s: ASSERT %s failed\n", __FUNCTION__, #x); \ + abort(); \ +} +#endif + +#define SOLID_RASTER_OP(_name, _size, _type, _equation) \ +static void \ +solid_rop_ ## _name ## _ ## _size (_type *ptr, int len, _type src) \ +{ \ + while (len--) { \ + _type dst = *ptr; \ + if (dst) /* avoid unused warning */; \ + *ptr = (_type)(_equation); \ + ptr++; \ + } \ +} \ + +#define TILED_RASTER_OP(_name, _size, _type, _equation) \ +static void \ +tiled_rop_ ## _name ## _ ## _size (_type *ptr, int len, _type *tile, _type *tile_end, int tile_width) \ +{ \ + while (len--) { \ + _type src = *tile; \ + _type dst = *ptr; \ + if (src) /* avoid unused warning */; \ + if (dst) /* avoid unused warning */; \ + *ptr = (_type)(_equation); \ + ptr++; \ + tile++; \ + if (tile == tile_end) \ + tile -= tile_width; \ + } \ +} \ + +#define COPY_RASTER_OP(_name, _size, _type, _equation) \ +static void \ + copy_rop_ ## _name ## _ ## _size (_type *ptr, _type *src_line, int len) \ +{ \ + while (len--) { \ + _type src = *src_line; \ + _type dst = *ptr; \ + if (src) /* avoid unused warning */; \ + if (dst) /* avoid unused warning */; \ + *ptr = (_type)(_equation); \ + ptr++; \ + src_line++; \ + } \ +} \ + +#define RASTER_OP(name, equation) \ + SOLID_RASTER_OP(name, 8, uint8_t, equation) \ + SOLID_RASTER_OP(name, 16, uint16_t, equation) \ + SOLID_RASTER_OP(name, 32, uint32_t, equation) \ + TILED_RASTER_OP(name, 8, uint8_t, equation) \ + TILED_RASTER_OP(name, 16, uint16_t, equation) \ + TILED_RASTER_OP(name, 32, uint32_t, equation) \ + COPY_RASTER_OP(name, 8, uint8_t, equation) \ + COPY_RASTER_OP(name, 16, uint16_t, equation) \ + COPY_RASTER_OP(name, 32, uint32_t, equation) + +RASTER_OP(clear, 0x0) +RASTER_OP(and, src & dst) +RASTER_OP(and_reverse, src & ~dst) +RASTER_OP(copy, src) +RASTER_OP(and_inverted, ~src & dst) +RASTER_OP(noop, dst) +RASTER_OP(xor, src ^ dst) +RASTER_OP(or, src | dst) +RASTER_OP(nor, ~src & ~dst) +RASTER_OP(equiv, ~src ^ dst) +RASTER_OP(invert, ~dst) +RASTER_OP(or_reverse, src | ~dst) +RASTER_OP(copy_inverted, ~src) +RASTER_OP(or_inverted, ~src | dst) +RASTER_OP(nand, ~src | ~dst) +RASTER_OP(set, 0xffffffff) + +typedef void (*solid_rop_8_func_t)(uint8_t *ptr, int len, uint8_t src); +typedef void (*solid_rop_16_func_t)(uint16_t *ptr, int len, uint16_t src); +typedef void (*solid_rop_32_func_t)(uint32_t *ptr, int len, uint32_t src); +typedef void (*tiled_rop_8_func_t)(uint8_t *ptr, int len, + uint8_t *tile, uint8_t *tile_end, int tile_width); +typedef void (*tiled_rop_16_func_t)(uint16_t *ptr, int len, + uint16_t *tile, uint16_t *tile_end, int tile_width); +typedef void (*tiled_rop_32_func_t)(uint32_t *ptr, int len, + uint32_t *tile, uint32_t *tile_end, int tile_width); +typedef void (*copy_rop_8_func_t)(uint8_t *ptr, uint8_t *src, int len); +typedef void (*copy_rop_16_func_t)(uint16_t *ptr, uint16_t *src, int len); +typedef void (*copy_rop_32_func_t)(uint32_t *ptr, uint32_t *src, int len); + +#define ROP_TABLE(_type, _size) \ +static void (*solid_rops_ ## _size[16]) (_type *ptr, int len, _type src) = { \ + solid_rop_clear_ ## _size, \ + solid_rop_and_ ## _size, \ + solid_rop_and_reverse_ ## _size, \ + solid_rop_copy_ ## _size, \ + solid_rop_and_inverted_ ## _size, \ + solid_rop_noop_ ## _size, \ + solid_rop_xor_ ## _size, \ + solid_rop_or_ ## _size, \ + solid_rop_nor_ ## _size, \ + solid_rop_equiv_ ## _size, \ + solid_rop_invert_ ## _size, \ + solid_rop_or_reverse_ ## _size, \ + solid_rop_copy_inverted_ ## _size, \ + solid_rop_or_inverted_ ## _size, \ + solid_rop_nand_ ## _size, \ + solid_rop_set_ ## _size \ +}; \ +static void (*tiled_rops_ ## _size[16]) (_type *ptr, int len, _type *tile, _type *tile_end, int tile_width) = { \ + tiled_rop_clear_ ## _size, \ + tiled_rop_and_ ## _size, \ + tiled_rop_and_reverse_ ## _size, \ + tiled_rop_copy_ ## _size, \ + tiled_rop_and_inverted_ ## _size, \ + tiled_rop_noop_ ## _size, \ + tiled_rop_xor_ ## _size, \ + tiled_rop_or_ ## _size, \ + tiled_rop_nor_ ## _size, \ + tiled_rop_equiv_ ## _size, \ + tiled_rop_invert_ ## _size, \ + tiled_rop_or_reverse_ ## _size, \ + tiled_rop_copy_inverted_ ## _size, \ + tiled_rop_or_inverted_ ## _size, \ + tiled_rop_nand_ ## _size, \ + tiled_rop_set_ ## _size \ +}; \ +static void (*copy_rops_ ## _size[16]) (_type *ptr, _type *tile, int len) = { \ + copy_rop_clear_ ## _size, \ + copy_rop_and_ ## _size, \ + copy_rop_and_reverse_ ## _size, \ + copy_rop_copy_ ## _size, \ + copy_rop_and_inverted_ ## _size, \ + copy_rop_noop_ ## _size, \ + copy_rop_xor_ ## _size, \ + copy_rop_or_ ## _size, \ + copy_rop_nor_ ## _size, \ + copy_rop_equiv_ ## _size, \ + copy_rop_invert_ ## _size, \ + copy_rop_or_reverse_ ## _size, \ + copy_rop_copy_inverted_ ## _size, \ + copy_rop_or_inverted_ ## _size, \ + copy_rop_nand_ ## _size, \ + copy_rop_set_ ## _size \ +}; + +ROP_TABLE(uint8_t, 8) +ROP_TABLE(uint16_t, 16) +ROP_TABLE(uint32_t, 32) + +void spice_pixman_fill_rect(pixman_image_t *dest, + int x, int y, + int width, int height, + uint32_t value) +{ + uint32_t *bits; + int stride, depth; + uint32_t byte_width; + uint8_t *byte_line; + + bits = pixman_image_get_data(dest); + stride = pixman_image_get_stride(dest); + depth = pixman_image_get_depth(dest); + /* stride is in bytes, depth in bits */ + + ASSERT(x >= 0); + ASSERT(y >= 0); + ASSERT(width > 0); + ASSERT(height > 0); + ASSERT(x + width <= pixman_image_get_width(dest)); + ASSERT(y + height <= pixman_image_get_height(dest)); + + if (depth == 24) { + depth = 32; /* Needed for pixman_fill */ + } + + if (pixman_fill(bits, + stride / 4, + depth, + x, y, + width, height, + value)) { + return; + } + + if (depth == 8) { + byte_line = ((uint8_t *)bits) + stride * y + x; + byte_width = width; + value = (value & 0xff) * 0x01010101; + } else if (depth == 16) { + byte_line = ((uint8_t *)bits) + stride * y + x * 2; + byte_width = 2 * width; + value = (value & 0xffff) * 0x00010001; + } else { + ASSERT (depth == 32 || depth == 24) + byte_line = ((uint8_t *)bits) + stride * y + x * 4; + byte_width = 4 * width; + } + + while (height--) { + int w; + uint8_t *d = byte_line; + + byte_line += stride; + w = byte_width; + + while (w >= 1 && ((unsigned long)d & 1)) { + *(uint8_t *)d = (value & 0xff); + w--; + d++; + } + + while (w >= 2 && ((unsigned long)d & 3)) { + *(uint16_t *)d = value; + w -= 2; + d += 2; + } + + while (w >= 4 && ((unsigned long)d & 7)) { + *(uint32_t *)d = value; + + w -= 4; + d += 4; + } + + while (w >= 4) { + *(uint32_t *)d = value; + + w -= 4; + d += 4; + } + + while (w >= 2) { + *(uint16_t *)d = value; + w -= 2; + d += 2; + } + + while (w >= 1) { + *(uint8_t *)d = (value & 0xff); + w--; + d++; + } + } +} + +void spice_pixman_fill_rect_rop(pixman_image_t *dest, + int x, int y, + int width, int height, + uint32_t value, + SpiceROP rop) +{ + uint32_t *bits; + int stride, depth; + uint8_t *byte_line; + + bits = pixman_image_get_data(dest); + stride = pixman_image_get_stride(dest); + depth = pixman_image_get_depth(dest); + /* stride is in bytes, depth in bits */ + + ASSERT(x >= 0); + ASSERT(y >= 0); + ASSERT(width > 0); + ASSERT(height > 0); + ASSERT(x + width <= pixman_image_get_width(dest)); + ASSERT(y + height <= pixman_image_get_height(dest)); + ASSERT(rop >= 0 && rop < 16); + + if (depth == 8) { + solid_rop_8_func_t rop_func = solid_rops_8[rop]; + + byte_line = ((uint8_t *)bits) + stride * y + x; + while (height--) { + rop_func((uint8_t *)byte_line, width, (uint8_t)value); + byte_line += stride; + } + + } else if (depth == 16) { + solid_rop_16_func_t rop_func = solid_rops_16[rop]; + + byte_line = ((uint8_t *)bits) + stride * y + x * 2; + while (height--) { + rop_func((uint16_t *)byte_line, width, (uint16_t)value); + byte_line += stride; + } + } else { + solid_rop_32_func_t rop_func = solid_rops_32[rop]; + + ASSERT (depth == 32 || depth == 24); + + byte_line = ((uint8_t *)bits) + stride * y + x * 4; + while (height--) { + rop_func((uint32_t *)byte_line, width, (uint32_t)value); + byte_line += stride; + } + } +} + +void spice_pixman_tile_rect(pixman_image_t *dest, + int x, int y, + int width, int height, + pixman_image_t *tile, + int offset_x, + int offset_y) +{ + uint32_t *bits, *tile_bits; + int stride, depth; + int tile_width, tile_height, tile_stride; + uint8_t *byte_line; + uint8_t *tile_line; + int tile_start_x, tile_start_y, tile_end_dx; + + bits = pixman_image_get_data(dest); + stride = pixman_image_get_stride(dest); + depth = pixman_image_get_depth(dest); + /* stride is in bytes, depth in bits */ + + tile_bits = pixman_image_get_data(tile); + tile_stride = pixman_image_get_stride(tile); + tile_width = pixman_image_get_width(tile); + tile_height = pixman_image_get_height(tile); + + ASSERT(x >= 0); + ASSERT(y >= 0); + ASSERT(width > 0); + ASSERT(height > 0); + ASSERT(x + width <= pixman_image_get_width(dest)); + ASSERT(y + height <= pixman_image_get_height(dest)); + ASSERT(depth == pixman_image_get_depth(tile)); + + tile_start_x = (x - offset_x) % tile_width; + if (tile_start_x < 0) { + tile_start_x += tile_width; + } + tile_start_y = (y - offset_y) % tile_height; + if (tile_start_y < 0) { + tile_start_y += tile_height; + } + tile_end_dx = tile_width - tile_start_x; + + if (depth == 8) { + byte_line = ((uint8_t *)bits) + stride * y + x; + tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x; + while (height--) { + tiled_rop_copy_8((uint8_t *)byte_line, width, + (uint8_t *)tile_line, (uint8_t *)tile_line + tile_end_dx, + tile_width); + byte_line += stride; + tile_line += tile_stride; + if (++tile_start_y == tile_height) { + tile_line -= tile_height * tile_stride; + tile_start_y = 0; + } + } + + } else if (depth == 16) { + byte_line = ((uint8_t *)bits) + stride * y + x * 2; + tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 2; + while (height--) { + tiled_rop_copy_16((uint16_t *)byte_line, width, + (uint16_t *)tile_line, (uint16_t *)tile_line + tile_end_dx, + tile_width); + byte_line += stride; + tile_line += tile_stride; + if (++tile_start_y == tile_height) { + tile_line -= tile_height * tile_stride; + tile_start_y = 0; + } + } + } else { + ASSERT (depth == 32 || depth == 24); + + byte_line = ((uint8_t *)bits) + stride * y + x * 4; + tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4; + while (height--) { + tiled_rop_copy_32((uint32_t *)byte_line, width, + (uint32_t *)tile_line, (uint32_t *)tile_line + tile_end_dx, + tile_width); + byte_line += stride; + tile_line += tile_stride; + if (++tile_start_y == tile_height) { + tile_line -= tile_height * tile_stride; + tile_start_y = 0; + } + } + } +} + +void spice_pixman_tile_rect_rop(pixman_image_t *dest, + int x, int y, + int width, int height, + pixman_image_t *tile, + int offset_x, + int offset_y, + SpiceROP rop) +{ + uint32_t *bits, *tile_bits; + int stride, depth; + int tile_width, tile_height, tile_stride; + uint8_t *byte_line; + uint8_t *tile_line; + int tile_start_x, tile_start_y, tile_end_dx; + + bits = pixman_image_get_data(dest); + stride = pixman_image_get_stride(dest); + depth = pixman_image_get_depth(dest); + /* stride is in bytes, depth in bits */ + + tile_bits = pixman_image_get_data(tile); + tile_stride = pixman_image_get_stride(tile); + tile_width = pixman_image_get_width(tile); + tile_height = pixman_image_get_height(tile); + + ASSERT(x >= 0); + ASSERT(y >= 0); + ASSERT(width > 0); + ASSERT(height > 0); + ASSERT(x + width <= pixman_image_get_width(dest)); + ASSERT(y + height <= pixman_image_get_height(dest)); + ASSERT(rop >= 0 && rop < 16); + ASSERT(depth == pixman_image_get_depth(tile)); + + tile_start_x = (x - offset_x) % tile_width; + if (tile_start_x < 0) { + tile_start_x += tile_width; + } + tile_start_y = (y - offset_y) % tile_height; + if (tile_start_y < 0) { + tile_start_y += tile_height; + } + tile_end_dx = tile_width - tile_start_x; + + if (depth == 8) { + tiled_rop_8_func_t rop_func = tiled_rops_8[rop]; + + byte_line = ((uint8_t *)bits) + stride * y + x; + tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x; + while (height--) { + rop_func((uint8_t *)byte_line, width, + (uint8_t *)tile_line, (uint8_t *)tile_line + tile_end_dx, + tile_width); + byte_line += stride; + tile_line += tile_stride; + if (++tile_start_y == tile_height) { + tile_line -= tile_height * tile_stride; + tile_start_y = 0; + } + } + + } else if (depth == 16) { + tiled_rop_16_func_t rop_func = tiled_rops_16[rop]; + + byte_line = ((uint8_t *)bits) + stride * y + x * 2; + tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 2; + while (height--) { + rop_func((uint16_t *)byte_line, width, + (uint16_t *)tile_line, (uint16_t *)tile_line + tile_end_dx, + tile_width); + byte_line += stride; + tile_line += tile_stride; + if (++tile_start_y == tile_height) { + tile_line -= tile_height * tile_stride; + tile_start_y = 0; + } + } + } else { + tiled_rop_32_func_t rop_func = tiled_rops_32[rop]; + + ASSERT (depth == 32 || depth == 24); + + byte_line = ((uint8_t *)bits) + stride * y + x * 4; + tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4; + while (height--) { + rop_func((uint32_t *)byte_line, width, + (uint32_t *)tile_line, (uint32_t *)tile_line + tile_end_dx, + tile_width); + byte_line += stride; + tile_line += tile_stride; + if (++tile_start_y == tile_height) { + tile_line -= tile_height * tile_stride; + tile_start_y = 0; + } + } + } +} + + +void spice_pixman_blit(pixman_image_t *dest, + pixman_image_t *src, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height) +{ + uint32_t *bits, *src_bits; + int stride, depth; + int src_width, src_height, src_stride; + uint8_t *byte_line; + uint8_t *src_line; + int byte_width; + + bits = pixman_image_get_data(dest); + stride = pixman_image_get_stride(dest); + depth = pixman_image_get_depth(dest); + /* stride is in bytes, depth in bits */ + + src_bits = pixman_image_get_data(src); + src_stride = pixman_image_get_stride(src); + src_width = pixman_image_get_width(src); + src_height = pixman_image_get_height(src); + + /* Clip source */ + if (src_x < 0) { + width += src_x; + dest_x -= src_x; + src_x = 0; + } + if (src_y < 0) { + height += src_y; + dest_y -= src_y; + src_y = 0; + } + if (src_x + width > src_width) { + width = src_width - src_x; + } + if (src_y + height > src_height) { + height = src_height - src_y; + } + + if (width <= 0 || height <= 0) { + return; + } + + ASSERT(src_x >= 0); + ASSERT(src_y >= 0); + ASSERT(dest_x >= 0); + ASSERT(dest_y >= 0); + ASSERT(width > 0); + ASSERT(height > 0); + ASSERT(dest_x + width <= pixman_image_get_width(dest)); + ASSERT(dest_y + height <= pixman_image_get_height(dest)); + ASSERT(src_x + width <= pixman_image_get_width(src)); + ASSERT(src_y + height <= pixman_image_get_height(src)); + ASSERT(depth == pixman_image_get_depth(src)); + + if (depth == 24) { + depth = 32; /* Needed for pixman_blt */ + } + + if (pixman_blt(src_bits, + bits, + src_stride / 4, + stride / 4, + depth, depth, + src_x, src_y, + dest_x, dest_y, + width, height)) { + return; + } + + if (depth == 8) { + byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x; + byte_width = width; + src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x; + } else if (depth == 16) { + byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 2; + byte_width = width * 2; + src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 2; + } else { + ASSERT (depth == 32 || depth == 24); + byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4; + byte_width = width * 4; + src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4; + } + + while (height--) { + memcpy(byte_line, src_line, byte_width); + byte_line += stride; + src_line += src_stride; + } +} + +void spice_pixman_blit_rop (pixman_image_t *dest, + pixman_image_t *src, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + SpiceROP rop) +{ + uint32_t *bits, *src_bits; + int stride, depth; + int src_width, src_height, src_stride; + uint8_t *byte_line; + uint8_t *src_line; + + bits = pixman_image_get_data(dest); + stride = pixman_image_get_stride(dest); + depth = pixman_image_get_depth(dest); + /* stride is in bytes, depth in bits */ + + src_bits = pixman_image_get_data(src); + src_stride = pixman_image_get_stride(src); + src_width = pixman_image_get_width(src); + src_height = pixman_image_get_height(src); + + /* Clip source */ + if (src_x < 0) { + width += src_x; + dest_x -= src_x; + src_x = 0; + } + if (src_y < 0) { + height += src_y; + dest_y -= src_y; + src_y = 0; + } + if (src_x + width > src_width) { + width = src_width - src_x; + } + if (src_y + height > src_height) { + height = src_height - src_y; + } + + if (width <= 0 || height <= 0) { + return; + } + + ASSERT(src_x >= 0); + ASSERT(src_y >= 0); + ASSERT(dest_x >= 0); + ASSERT(dest_y >= 0); + ASSERT(width > 0); + ASSERT(height > 0); + ASSERT(dest_x + width <= pixman_image_get_width(dest)); + ASSERT(dest_y + height <= pixman_image_get_height(dest)); + ASSERT(src_x + width <= pixman_image_get_width(src)); + ASSERT(src_y + height <= pixman_image_get_height(src)); + ASSERT(depth == pixman_image_get_depth(src)); + + if (depth == 8) { + copy_rop_8_func_t rop_func = copy_rops_8[rop]; + + byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x; + src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x; + + while (height--) { + rop_func((uint8_t *)byte_line, (uint8_t *)src_line, width); + byte_line += stride; + src_line += src_stride; + } + } else if (depth == 16) { + copy_rop_16_func_t rop_func = copy_rops_16[rop]; + + byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 2; + src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 2; + + while (height--) { + rop_func((uint16_t *)byte_line, (uint16_t *)src_line, width); + byte_line += stride; + src_line += src_stride; + } + } else { + copy_rop_32_func_t rop_func = copy_rops_32[rop]; + + ASSERT (depth == 32 || depth == 24); + byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4; + src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4; + + while (height--) { + rop_func((uint32_t *)byte_line, (uint32_t *)src_line, width); + byte_line += stride; + src_line += src_stride; + } + } + +} + +void spice_pixman_blit_colorkey (pixman_image_t *dest, + pixman_image_t *src, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + uint32_t transparent_color) +{ + uint32_t *bits, *src_bits; + int stride, depth; + int src_width, src_height, src_stride; + uint8_t *byte_line; + uint8_t *src_line; + int x; + + bits = pixman_image_get_data(dest); + stride = pixman_image_get_stride(dest); + depth = pixman_image_get_depth(dest); + /* stride is in bytes, depth in bits */ + + src_bits = pixman_image_get_data(src); + src_stride = pixman_image_get_stride(src); + src_width = pixman_image_get_width(src); + src_height = pixman_image_get_height(src); + + /* Clip source */ + if (src_x < 0) { + width += src_x; + dest_x -= src_x; + src_x = 0; + } + if (src_y < 0) { + height += src_y; + dest_y -= src_y; + src_y = 0; + } + if (src_x + width > src_width) { + width = src_width - src_x; + } + if (src_y + height > src_height) { + height = src_height - src_y; + } + + if (width <= 0 || height <= 0) { + return; + } + + ASSERT(src_x >= 0); + ASSERT(src_y >= 0); + ASSERT(dest_x >= 0); + ASSERT(dest_y >= 0); + ASSERT(width > 0); + ASSERT(height > 0); + ASSERT(dest_x + width <= pixman_image_get_width(dest)); + ASSERT(dest_y + height <= pixman_image_get_height(dest)); + ASSERT(src_x + width <= pixman_image_get_width(src)); + ASSERT(src_y + height <= pixman_image_get_height(src)); + ASSERT(depth == pixman_image_get_depth(src)); + + if (depth == 8) { + byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x; + src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x; + + while (height--) { + uint8_t *d = (uint8_t *)byte_line; + uint8_t *s = (uint8_t *)byte_line; + + s = (uint8_t *)src_line; + for (x = 0; x < width; x++) { + uint8_t val = *s; + if (val != (uint8_t)transparent_color) { + *d = val; + } + s++; d++; + } + + byte_line += stride; + src_line += src_stride; + } + } else if (depth == 16) { + byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 2; + src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 2; + + while (height--) { + uint16_t *d = (uint16_t *)byte_line; + uint16_t *s = (uint16_t *)byte_line; + + s = (uint16_t *)src_line; + for (x = 0; x < width; x++) { + uint16_t val = *s; + if (val != (uint16_t)transparent_color) { + *d = val; + } + s++; d++; + } + + byte_line += stride; + src_line += src_stride; + } + } else { + ASSERT (depth == 32 || depth == 24); + byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4; + src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4; + + while (height--) { + uint32_t *d = (uint32_t *)byte_line; + uint32_t *s = (uint32_t *)byte_line; + + s = (uint32_t *)src_line; + for (x = 0; x < width; x++) { + uint32_t val = *s; + if (val != (0xffffff & transparent_color)) { + *d = val; + } + s++; d++; + } + + byte_line += stride; + src_line += src_stride; + } + } +} + +static void copy_bits_up(uint8_t *data, const int stride, + const int src_x, const int src_y, + const int width, const int height, + const int dest_x, const int dest_y) +{ + uint8_t *src = data + src_y * stride + src_x * sizeof(uint32_t); + uint8_t *dest = data + dest_y * stride + dest_x * sizeof(uint32_t); + uint8_t *end = dest + height * stride; + for (; dest != end; dest += stride, src += stride) { + memcpy(dest, src, width * sizeof(uint32_t)); + } +} + +static void copy_bits_down(uint8_t *data, const int stride, + const int src_x, const int src_y, + const int width, const int height, + const int dest_x, const int dest_y) +{ + uint8_t *src = data + (src_y + height - 1) * stride + src_x * sizeof(uint32_t); + uint8_t *end = data + (dest_y - 1) * stride + dest_x * sizeof(uint32_t); + uint8_t *dest = end + height * stride; + + for (; dest != end; dest -= stride, src -= stride) { + memcpy(dest, src, width * sizeof(uint32_t)); + } +} + +static void copy_bits_same_line(uint8_t *data, const int stride, + const int src_x, const int src_y, + const int width, const int height, + const int dest_x, const int dest_y) +{ + uint8_t *src = data + src_y * stride + src_x * sizeof(uint32_t); + uint8_t *dest = data + dest_y * stride + dest_x * sizeof(uint32_t); + uint8_t *end = dest + height * stride; + for (; dest != end; dest += stride, src += stride) { + memmove(dest, src, width * sizeof(uint32_t)); + } +} + +void spice_pixman_copy_rect (pixman_image_t *image, + int src_x, int src_y, + int width, int height, + int dest_x, int dest_y) +{ + uint8_t *data; + int stride; + + data = (uint8_t *)pixman_image_get_data(image); + stride = pixman_image_get_stride(image); + + ASSERT(pixman_image_get_depth(image) == 24 || + pixman_image_get_depth(image) == 32); + + if (dest_y > src_y) { + copy_bits_down(data, stride, + src_x, src_y, + width, height, + dest_x, dest_y); + } else if (dest_y < src_y) { + copy_bits_up(data, stride, + src_x, src_y, + width, height, + dest_x, dest_y); + } else { + copy_bits_same_line(data, stride, + src_x, src_y, + width, height, + dest_x, dest_y); + } +} + +pixman_bool_t spice_pixman_region32_init_rects (pixman_region32_t *region, + const SpiceRect *rects, + int count) +{ + pixman_box32_t boxes_array[10]; + pixman_box32_t *boxes; + pixman_bool_t res; + int i; + + if (count < 10) { + boxes = boxes_array; + } else { + boxes = (pixman_box32_t *)malloc(sizeof(pixman_box32_t) * count); + if (boxes == NULL) { + return FALSE; + } + } + + for (i = 0; i < count; i++) { + boxes[i].x1 = rects[i].left; + boxes[i].y1 = rects[i].top; + boxes[i].x2 = rects[i].right; + boxes[i].y2 = rects[i].bottom; + } + + res = pixman_region32_init_rects(region, boxes, count); + + if (count >= 10) { + free(boxes); + } + + return res; +} diff --git a/common/pixman_utils.h b/common/pixman_utils.h new file mode 100644 index 00000000..fb8dd02f --- /dev/null +++ b/common/pixman_utils.h @@ -0,0 +1,103 @@ +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (C) 2009 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _H__PIXMAN_UTILS +#define _H__PIXMAN_UTILS + +#include <pixman.h> + +#include <spice/draw.h> + +/* This lists all possible 2 argument binary raster ops. + * This enum has the same values as the X11 GXcopy type + * and same as the GL constants (GL_AND etc) if you + * or it with 0x1500. However it is not exactly the + * same as the win32 ROP2 type (they use another order). + */ +typedef enum { + SPICE_ROP_CLEAR, /* 0x0 0 */ + SPICE_ROP_AND, /* 0x1 src AND dst */ + SPICE_ROP_AND_REVERSE, /* 0x2 src AND NOT dst */ + SPICE_ROP_COPY, /* 0x3 src */ + SPICE_ROP_AND_INVERTED, /* 0x4 (NOT src) AND dst */ + SPICE_ROP_NOOP, /* 0x5 dst */ + SPICE_ROP_XOR, /* 0x6 src XOR dst */ + SPICE_ROP_OR, /* 0x7 src OR dst */ + SPICE_ROP_NOR, /* 0x8 (NOT src) AND (NOT dst) */ + SPICE_ROP_EQUIV, /* 0x9 (NOT src) XOR dst */ + SPICE_ROP_INVERT, /* 0xa NOT dst */ + SPICE_ROP_OR_REVERSE, /* 0xb src OR (NOT dst) */ + SPICE_ROP_COPY_INVERTED, /* 0xc NOT src */ + SPICE_ROP_OR_INVERTED, /* 0xd (NOT src) OR dst */ + SPICE_ROP_NAND, /* 0xe (NOT src) OR (NOT dst) */ + SPICE_ROP_SET /* 0xf 1 */ +} SpiceROP; + + +void spice_pixman_region32_init_from_bitmap(pixman_region32_t *region, + uint32_t *data, + int width, int height, + int stride); +pixman_bool_t spice_pixman_region32_init_rects(pixman_region32_t *region, + const SpiceRect *rects, + int count); +void spice_pixman_fill_rect(pixman_image_t *dest, + int x, int y, + int w, int h, + uint32_t value); +void spice_pixman_fill_rect_rop(pixman_image_t *dest, + int x, int y, + int w, int h, + uint32_t value, + SpiceROP rop); +void spice_pixman_tile_rect(pixman_image_t *dest, + int x, int y, + int w, int h, + pixman_image_t *tile, + int offset_x, + int offset_y); +void spice_pixman_tile_rect_rop(pixman_image_t *dest, + int x, int y, + int w, int h, + pixman_image_t *tile, + int offset_x, + int offset_y, + SpiceROP rop); +void spice_pixman_blit(pixman_image_t *dest, + pixman_image_t *src, + int src_x, int src_y, + int dest_x, int dest_y, + int w, int h); +void spice_pixman_blit_rop(pixman_image_t *dest, + pixman_image_t *src, + int src_x, int src_y, + int dest_x, int dest_y, + int w, int h, + SpiceROP rop); +void spice_pixman_blit_colorkey(pixman_image_t *dest, + pixman_image_t *src, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + uint32_t transparent_color); +void spice_pixman_copy_rect(pixman_image_t *image, + int src_x, int src_y, + int w, int h, + int dest_x, int dest_y); + +#endif /* _H__PIXMAN_UTILS */ diff --git a/server/Makefile.am b/server/Makefile.am index 03f15a3b..b2bea005 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -20,6 +20,7 @@ INCLUDES = \ COMMON_SRCS = \ $(top_srcdir)/common/cairo_canvas.c \ + $(top_srcdir)/common/pixman_utils.c \ $(top_srcdir)/common/gl_canvas.c \ $(top_srcdir)/common/region.c \ $(top_srcdir)/common/glc.c \ |