316 lines
9.0 KiB
C
316 lines
9.0 KiB
C
|
/*
|
||
|
* Copyright © 2009 Red Hat, Inc.
|
||
|
* Copyright © 2000 SuSE, Inc.
|
||
|
* Copyright © 2007 Red Hat, Inc.
|
||
|
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
|
||
|
* 2005 Lars Knoll & Zack Rusin, Trolltech
|
||
|
* 2008 Aaron Plattner, NVIDIA Corporation
|
||
|
*
|
||
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
||
|
* documentation for any purpose is hereby granted without fee, provided that
|
||
|
* the above copyright notice appear in all copies and that both that
|
||
|
* copyright notice and this permission notice appear in supporting
|
||
|
* documentation, and that the name of Red Hat not be used in advertising or
|
||
|
* publicity pertaining to distribution of the software without specific,
|
||
|
* written prior permission. Red Hat makes no representations about the
|
||
|
* suitability of this software for any purpose. It is provided "as is"
|
||
|
* without express or implied warranty.
|
||
|
*
|
||
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||
|
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||
|
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||
|
* SOFTWARE.
|
||
|
*/
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include <config.h>
|
||
|
#endif
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <math.h>
|
||
|
#include <limits.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include "pixman-private.h"
|
||
|
#include "pixman-combine32.h"
|
||
|
#include "pixman-private.h"
|
||
|
|
||
|
#define SCANLINE_BUFFER_LENGTH 8192
|
||
|
|
||
|
static void
|
||
|
general_composite_rect (pixman_implementation_t *imp,
|
||
|
pixman_op_t op,
|
||
|
pixman_image_t * src,
|
||
|
pixman_image_t * mask,
|
||
|
pixman_image_t * dest,
|
||
|
int32_t src_x,
|
||
|
int32_t src_y,
|
||
|
int32_t mask_x,
|
||
|
int32_t mask_y,
|
||
|
int32_t dest_x,
|
||
|
int32_t dest_y,
|
||
|
int32_t width,
|
||
|
int32_t height)
|
||
|
{
|
||
|
uint64_t stack_scanline_buffer[(SCANLINE_BUFFER_LENGTH * 3 + 7) / 8];
|
||
|
uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer;
|
||
|
uint8_t *src_buffer, *mask_buffer, *dest_buffer;
|
||
|
fetch_scanline_t fetch_src = NULL, fetch_mask = NULL, fetch_dest = NULL;
|
||
|
pixman_combine_32_func_t compose;
|
||
|
store_scanline_t store;
|
||
|
source_image_class_t src_class, mask_class;
|
||
|
pixman_bool_t component_alpha;
|
||
|
uint32_t *bits;
|
||
|
int32_t stride;
|
||
|
int narrow, Bpp;
|
||
|
int i;
|
||
|
|
||
|
narrow =
|
||
|
(src->common.flags & FAST_PATH_NARROW_FORMAT) &&
|
||
|
(!mask || mask->common.flags & FAST_PATH_NARROW_FORMAT) &&
|
||
|
(dest->common.flags & FAST_PATH_NARROW_FORMAT);
|
||
|
Bpp = narrow ? 4 : 8;
|
||
|
|
||
|
if (width * Bpp > SCANLINE_BUFFER_LENGTH)
|
||
|
{
|
||
|
scanline_buffer = pixman_malloc_abc (width, 3, Bpp);
|
||
|
|
||
|
if (!scanline_buffer)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
src_buffer = scanline_buffer;
|
||
|
mask_buffer = src_buffer + width * Bpp;
|
||
|
dest_buffer = mask_buffer + width * Bpp;
|
||
|
|
||
|
src_class = _pixman_image_classify (src,
|
||
|
src_x, src_y,
|
||
|
width, height);
|
||
|
|
||
|
mask_class = SOURCE_IMAGE_CLASS_UNKNOWN;
|
||
|
|
||
|
if (mask)
|
||
|
{
|
||
|
mask_class = _pixman_image_classify (mask,
|
||
|
src_x, src_y,
|
||
|
width, height);
|
||
|
}
|
||
|
|
||
|
if (op == PIXMAN_OP_CLEAR)
|
||
|
fetch_src = NULL;
|
||
|
else if (narrow)
|
||
|
fetch_src = _pixman_image_get_scanline_32;
|
||
|
else
|
||
|
fetch_src = _pixman_image_get_scanline_64;
|
||
|
|
||
|
if (!mask || op == PIXMAN_OP_CLEAR)
|
||
|
fetch_mask = NULL;
|
||
|
else if (narrow)
|
||
|
fetch_mask = _pixman_image_get_scanline_32;
|
||
|
else
|
||
|
fetch_mask = _pixman_image_get_scanline_64;
|
||
|
|
||
|
if (op == PIXMAN_OP_CLEAR || op == PIXMAN_OP_SRC)
|
||
|
fetch_dest = NULL;
|
||
|
else if (narrow)
|
||
|
fetch_dest = _pixman_image_get_scanline_32;
|
||
|
else
|
||
|
fetch_dest = _pixman_image_get_scanline_64;
|
||
|
|
||
|
if (narrow)
|
||
|
store = _pixman_image_store_scanline_32;
|
||
|
else
|
||
|
store = _pixman_image_store_scanline_64;
|
||
|
|
||
|
/* Skip the store step and composite directly into the
|
||
|
* destination if the output format of the compose func matches
|
||
|
* the destination format.
|
||
|
*
|
||
|
* If the destination format is a8r8g8b8 then we can always do
|
||
|
* this. If it is x8r8g8b8, then we can only do it if the
|
||
|
* operator doesn't make use of destination alpha.
|
||
|
*/
|
||
|
if ((dest->bits.format == PIXMAN_a8r8g8b8) ||
|
||
|
(dest->bits.format == PIXMAN_x8r8g8b8 &&
|
||
|
(op == PIXMAN_OP_OVER ||
|
||
|
op == PIXMAN_OP_ADD ||
|
||
|
op == PIXMAN_OP_SRC ||
|
||
|
op == PIXMAN_OP_CLEAR ||
|
||
|
op == PIXMAN_OP_IN_REVERSE ||
|
||
|
op == PIXMAN_OP_OUT_REVERSE ||
|
||
|
op == PIXMAN_OP_DST)))
|
||
|
{
|
||
|
if (narrow &&
|
||
|
!dest->common.alpha_map &&
|
||
|
!dest->bits.write_func)
|
||
|
{
|
||
|
store = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!store)
|
||
|
{
|
||
|
bits = dest->bits.bits;
|
||
|
stride = dest->bits.rowstride;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bits = NULL;
|
||
|
stride = 0;
|
||
|
}
|
||
|
|
||
|
component_alpha =
|
||
|
fetch_src &&
|
||
|
fetch_mask &&
|
||
|
mask &&
|
||
|
mask->common.type == BITS &&
|
||
|
mask->common.component_alpha &&
|
||
|
PIXMAN_FORMAT_RGB (mask->bits.format);
|
||
|
|
||
|
if (narrow)
|
||
|
{
|
||
|
if (component_alpha)
|
||
|
compose = _pixman_implementation_combine_32_ca;
|
||
|
else
|
||
|
compose = _pixman_implementation_combine_32;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (component_alpha)
|
||
|
compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64_ca;
|
||
|
else
|
||
|
compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64;
|
||
|
}
|
||
|
|
||
|
if (!compose)
|
||
|
return;
|
||
|
|
||
|
if (!fetch_mask)
|
||
|
mask_buffer = NULL;
|
||
|
|
||
|
for (i = 0; i < height; ++i)
|
||
|
{
|
||
|
/* fill first half of scanline with source */
|
||
|
if (fetch_src)
|
||
|
{
|
||
|
if (fetch_mask)
|
||
|
{
|
||
|
/* fetch mask before source so that fetching of
|
||
|
source can be optimized */
|
||
|
fetch_mask (mask, mask_x, mask_y + i,
|
||
|
width, (void *)mask_buffer, 0);
|
||
|
|
||
|
if (mask_class == SOURCE_IMAGE_CLASS_HORIZONTAL)
|
||
|
fetch_mask = NULL;
|
||
|
}
|
||
|
|
||
|
if (src_class == SOURCE_IMAGE_CLASS_HORIZONTAL)
|
||
|
{
|
||
|
fetch_src (src, src_x, src_y + i,
|
||
|
width, (void *)src_buffer, 0);
|
||
|
fetch_src = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fetch_src (src, src_x, src_y + i,
|
||
|
width, (void *)src_buffer, (void *)mask_buffer);
|
||
|
}
|
||
|
}
|
||
|
else if (fetch_mask)
|
||
|
{
|
||
|
fetch_mask (mask, mask_x, mask_y + i,
|
||
|
width, (void *)mask_buffer, 0);
|
||
|
}
|
||
|
|
||
|
if (store)
|
||
|
{
|
||
|
/* fill dest into second half of scanline */
|
||
|
if (fetch_dest)
|
||
|
{
|
||
|
fetch_dest (dest, dest_x, dest_y + i,
|
||
|
width, (void *)dest_buffer, 0);
|
||
|
}
|
||
|
|
||
|
/* blend */
|
||
|
compose (imp->toplevel, op,
|
||
|
(void *)dest_buffer,
|
||
|
(void *)src_buffer,
|
||
|
(void *)mask_buffer,
|
||
|
width);
|
||
|
|
||
|
/* write back */
|
||
|
store (&(dest->bits), dest_x, dest_y + i, width,
|
||
|
(void *)dest_buffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* blend */
|
||
|
compose (imp->toplevel, op,
|
||
|
bits + (dest_y + i) * stride + dest_x,
|
||
|
(void *)src_buffer, (void *)mask_buffer, width);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (scanline_buffer != (uint8_t *) stack_scanline_buffer)
|
||
|
free (scanline_buffer);
|
||
|
}
|
||
|
|
||
|
static const pixman_fast_path_t general_fast_path[] =
|
||
|
{
|
||
|
{ PIXMAN_OP_any, PIXMAN_any, 0, PIXMAN_any, 0, PIXMAN_any, 0, general_composite_rect },
|
||
|
{ PIXMAN_OP_NONE }
|
||
|
};
|
||
|
|
||
|
static pixman_bool_t
|
||
|
general_blt (pixman_implementation_t *imp,
|
||
|
uint32_t * src_bits,
|
||
|
uint32_t * dst_bits,
|
||
|
int src_stride,
|
||
|
int dst_stride,
|
||
|
int src_bpp,
|
||
|
int dst_bpp,
|
||
|
int src_x,
|
||
|
int src_y,
|
||
|
int dst_x,
|
||
|
int dst_y,
|
||
|
int width,
|
||
|
int height)
|
||
|
{
|
||
|
/* We can't blit unless we have sse2 or mmx */
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static pixman_bool_t
|
||
|
general_fill (pixman_implementation_t *imp,
|
||
|
uint32_t * bits,
|
||
|
int stride,
|
||
|
int bpp,
|
||
|
int x,
|
||
|
int y,
|
||
|
int width,
|
||
|
int height,
|
||
|
uint32_t xor)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pixman_implementation_t *
|
||
|
_pixman_implementation_create_general (void)
|
||
|
{
|
||
|
pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path);
|
||
|
|
||
|
_pixman_setup_combiner_functions_32 (imp);
|
||
|
_pixman_setup_combiner_functions_64 (imp);
|
||
|
|
||
|
imp->blt = general_blt;
|
||
|
imp->fill = general_fill;
|
||
|
|
||
|
return imp;
|
||
|
}
|
||
|
|