import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

View file

234
gfx/cairo/libpixman/INSTALL Normal file
View file

@ -0,0 +1,234 @@
Installation Instructions
*************************
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
2006 Free Software Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that the
`configure' script does not know about. Run `./configure --help' for
details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' cannot figure out automatically,
but needs to determine by the type of machine the package will run on.
Usually, assuming the package is built to be run on the _same_
architectures, `configure' can figure that out, but if it prints a
message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share, you
can create a site shell script called `config.site' that gives default
values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf bug. Until the bug is fixed you can use this workaround:
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

0
gfx/cairo/libpixman/NEWS Normal file
View file

View file

139
gfx/cairo/libpixman/TODO Normal file
View file

@ -0,0 +1,139 @@
- Go through things marked FIXME
- Add calls to prepare and finish access where necessary. grep for
ACCESS_MEM, and make sure they are correctly wrapped in prepare
and finish.
- restore READ/WRITE in the fbcompose combiners since they sometimes
store directly to destination drawables.
- It probably makes sense to move the more strange X region API
into pixman as well, but guarded with PIXMAN_XORG_COMPATIBILITY
- Reinstate the FbBits typedef? At the moment we don't
even have the FbBits type; we just use uint32_t everywhere.
Keith says in bug 2335:
The 64-bit code in fb (pixman) is probably broken; it hasn't been
used in quite some time as PCI (and AGP) is 32-bits wide, so
doing things 64-bits at a time is a net loss. To quickly fix
this, I suggest just using 32-bit datatypes by setting
IC_SHIFT to 5 for all machines.
- Consider whether calling regions region16 is really such a great
idea Vlad wants 32 bit regions for Cairo. This will break X server
ABI, but should otherwise be mostly harmless, though a
pixman_region_get_boxes16() may be useful.
- Make source clipping optional.
- done: source clipping happens through an indirection.
still needs to make the indirection settable. (And call it
from X)
- Consider optimizing the 8/16 bit solid fills in pixman-util.c by
storing more than one value at a time.
- Add an image cache to prevent excessive malloc/free. Note that pixman
needs to be thread safe when used from cairo.
- Review the pixman_format_code_t enum to make sure it will support
future formats. Some formats we will probably need:
ARGB/ABGR with 16/32/64 bit integer/floating channels
YUV2,
YV12
Also we may need the ability to distinguish between PICT_c8 and
PICT_x4c4. (This could be done by interpreting the A channel as
the depth for TYPE_COLOR and TYPE_GRAY formats).
A possibility may be to reserve the two top bits and make them
encode "number of places to shift the channel widths given" Since
these bits are 00 at the moment everything will continue to work,
but these additional widths will be allowed:
All even widths between 18-32
All multiples of four widths between 33 and 64
All multiples of eight between 64 and 128
This means things like r21g22b21 won't work - is that worth
worrying about? I don't think so. And of course the bpp field
can't handle a depth of over 256, so > 64 bit channels arent'
really all that useful.
We could reserve one extra bit to indicate floating point, but
we may also just add
PIXMAN_TYPE_ARGB_FLOAT
PIXMAN_TYPE_BGRA_FLOAT
PIXMAN_TYPE_A_FLOAT
image types. With five bits we can support up to 32 different
format types, which should be enough for everybody, even if we
decide to support all the various video formats here:
http://www.fourcc.org/yuv.php
It may make sense to have a PIXMAN_TYPE_YUV, and then use the
channel bits to specify the exact subtype.
What about color spaces such a linear vs. srGB etc.?
done:
- Run cairo test suite; fix bugs
- one bug in source-scale-clip
- Remove the warning suppression in the ACCESS_MEM macro and fix the
warnings that are real
- irrelevant now.
- make the wrapper functions global instead of image specific
- this won't work since pixman is linked to both fb and wfb
- Add non-mmx solid fill
- Make sure the endian-ness macros are defined correctly.
- The rectangles in a region probably shouldn't be returned const as
the X server will be changing them.
- Right now we _always_ have a clip region, which is empty by default.
Why does this work at all? It probably doesn't. The server
distinguishes two cases, one where nothing is clipped (CT_NONE), and
one where there is a clip region (CT_REGION).
- Default clip region should be the full image
- Test if pseudo color still works. It does, but it also shows that
copying a pixman_indexed_t on every composite operation is not
going to fly. So, for now set_indexed() does not copy the
indexed table.
Also just the malloc() to allocate a pixman image shows up pretty
high.
Options include
- Make all the setters not copy their arguments
- Possibly combined with going back to the stack allocated
approach that we already use for regions.
- Keep a cached pixman_image_t around for every picture. It would
have to be kept uptodate every time something changes about the
picture.
- Break the X server ABI and simply have the relevant parameter
stored in the pixman image. This would have the additional benefits
that:
- We can get rid of the annoying repeat field which is duplicated
elsewhere.
- We can use pixman_color_t and pixman_gradient_stop_t
etc. instead of the types that are defined in
renderproto.h

View file

@ -0,0 +1,10 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
# The ARM asm functions here don't appreciate being called by functions
# compiled with -mapcs-frame. See bug 832752.
CXXFLAGS := $(filter-out -mapcs-frame,$(CXXFLAGS))
CFLAGS := $(filter-out -mapcs-frame,$(CFLAGS))

View file

@ -0,0 +1,86 @@
$usage = "Usage: combine.pl { 8 | 16 } < pixman-combine.c.template";
$#ARGV == 0 or die $usage;
# Get the component size.
$size = int($ARGV[0]);
$size == 8 or $size == 16 or die $usage;
$pixel_size = $size * 4;
$half_pixel_size = $size * 2;
sub mask {
my $str = shift;
my $suffix;
$suffix = "ULL" if $size > 8;
return "0x" . $str . $suffix;
}
# Generate mask strings.
$nibbles = $size / 4;
$mask = "f" x $nibbles;
$zero_mask = "0" x $nibbles;
$one_half = "8" . "0" x ($nibbles - 1);
print "/* WARNING: This file is generated by combine.pl from combine.inc.\n";
print " Please edit one of those files rather than this one. */\n";
print "\n";
print "#line 1 \"pixman-combine.c.template\"\n";
$mask_ = mask($mask);
$one_half_ = mask($one_half);
$g_mask = mask($mask . $zero_mask);
$b_mask = mask($mask . $zero_mask x 2);
$a_mask = mask($mask . $zero_mask x 3);
$rb_mask = mask($mask . $zero_mask . $mask);
$ag_mask = mask($mask . $zero_mask . $mask . $zero_mask);
$rb_one_half = mask($one_half . $zero_mask . $one_half);
$rb_mask_plus_one = mask("1" . $zero_mask x 2 . "1" . $zero_mask);
while (<STDIN>) {
# Mask and 1/2 value for a single component.
s/#define COMPONENT_SIZE\b/$& $size/;
s/#define MASK\b/$& $mask_/;
s/#define ONE_HALF\b/$& $one_half_/;
# Shifts and masks for green, blue, and alpha.
s/#define G_SHIFT\b/$& $size/;
s/#define R_SHIFT\b/$& $size * 2/;
s/#define A_SHIFT\b/$& $size * 3/;
s/#define G_MASK\b/$& $g_mask/;
s/#define R_MASK\b/$& $b_mask/;
s/#define A_MASK\b/$& $a_mask/;
# Special values for dealing with red + blue at the same time.
s/#define RB_MASK\b/$& $rb_mask/;
s/#define AG_MASK\b/$& $ag_mask/;
s/#define RB_ONE_HALF\b/$& $rb_one_half/;
s/#define RB_MASK_PLUS_ONE\b/$& $rb_mask_plus_one/;
# Add 32/64 suffix to combining function types.
s/\bCombineFunc\b/CombineFunc$pixel_size/;
s/\bFbComposeFunctions\b/FbComposeFunctions$pixel_size/;
s/combine_width/combine_$pixel_size/;
s/_pixman_setup_combiner_functions_width/_pixman_setup_combiner_functions_$pixel_size/;
s/UNc/UN$size/g;
s/ALPHA_c/ALPHA_$size/g;
s/RED_c/RED_$size/g;
s/GREEN_c/GREEN_$size/g;
s/BLUE_c/BLUE_$size/g;
# Convert comp*_t values into the appropriate real types.
s/comp1_t/uint${size}_t/g;
s/comp2_t/uint${half_pixel_size}_t/g;
s/comp4_t/uint${pixel_size}_t/g;
# Change the function table name for the 64-bit version.
s/pixman_composeFunctions/pixman_composeFunctions64/ if $size == 16;
# Change the header for the 64-bit version
s/pixman-combine.h/pixman-combine64.h/ if $size == 16;
s/pixman-combine.h/pixman-combine32.h/ if $size == 8;
print;
}

View file

@ -0,0 +1,163 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS += [
'pixman-version.h',
'pixman.h',
]
# Apple's arm assembler doesn't support the same syntax as
# the standard GNU assembler, so use the C fallback paths for now.
# This may be fixable if clang's ARM/iOS assembler improves into a
# viable solution in the future.
if CONFIG['OS_ARCH'] != 'Darwin' and CONFIG['GNU_CC']:
if CONFIG['HAVE_ARM_NEON']:
SOURCES += [
'pixman-arm-neon-asm-bilinear.S',
'pixman-arm-neon-asm.S',
]
if CONFIG['HAVE_ARM_SIMD']:
SOURCES += [
'pixman-arm-simd-asm-scaled.S',
'pixman-arm-simd-asm.S',
]
if CONFIG['CLANG_CXX']:
ASFLAGS += [
'-no-integrated-as',
]
SOURCES += [
'pixman-access-accessors.c',
'pixman-access.c',
'pixman-arm.c',
'pixman-bits-image.c',
'pixman-combine-float.c',
'pixman-combine16.c',
'pixman-combine32.c',
'pixman-conical-gradient.c',
'pixman-edge-accessors.c',
'pixman-edge.c',
'pixman-fast-path.c',
'pixman-filter.c',
'pixman-general.c',
'pixman-glyph.c',
'pixman-gradient-walker.c',
'pixman-image.c',
'pixman-implementation.c',
'pixman-linear-gradient.c',
'pixman-matrix.c',
'pixman-mips.c',
'pixman-noop.c',
'pixman-ppc.c',
'pixman-radial-gradient.c',
'pixman-region16.c',
'pixman-region32.c',
'pixman-solid-fill.c',
'pixman-trap.c',
'pixman-utils.c',
'pixman-x86.c',
'pixman.c',
]
# We allow warnings for third-party code that can be updated from upstream.
ALLOW_COMPILER_WARNINGS = True
FINAL_LIBRARY = 'gkmedias'
LOCAL_INCLUDES += [
'../../cairo/src',
]
if CONFIG['MOZ_USE_PTHREADS']:
DEFINES['HAVE_PTHREAD_SETSPECIFIC'] = True
if CONFIG['_MSC_VER']:
DEFINES['PIXMAN_USE_XP_DLL_TLS_WORKAROUND'] = True
DEFINES['PACKAGE'] = 'mozpixman'
DEFINES['_USE_MATH_DEFINES'] = True
use_mmx = False
use_sse2 = False
use_vmx = False
use_arm_simd_gcc = False
use_arm_neon_gcc = False
if '86' in CONFIG['OS_TEST']:
use_sse2 = True
if '64' not in CONFIG['OS_TEST']:
if CONFIG['_MSC_VER']:
use_mmx = True
if CONFIG['GNU_CC']:
use_mmx = True
elif 'ppc' in CONFIG['OS_TEST']:
if CONFIG['GNU_CC']:
use_vmx = True
# Apple's arm assembler doesn't support the same syntax as
# the standard GNU assembler, so use the C fallback paths for now.
# This may be fixable if clang's ARM/iOS assembler improves into a
# viable solution in the future.
elif 'arm' in CONFIG['OS_TEST']:
if CONFIG['OS_ARCH'] != 'Darwin':
if CONFIG['HAVE_ARM_SIMD']:
use_arm_simd_gcc = True
if CONFIG['HAVE_ARM_NEON']:
use_arm_neon_gcc = True
if use_mmx:
DEFINES['USE_MMX'] = True
SOURCES += ['pixman-mmx.c']
SOURCES['pixman-mmx.c'].flags += CONFIG['MMX_FLAGS']
if CONFIG['GNU_CC']:
SOURCES['pixman-mmx.c'].flags += [
'-Winline',
'--param inline-unit-growth=10000',
'--param large-function-growth=10000',
]
if use_sse2:
DEFINES['USE_SSE'] = True
DEFINES['USE_SSE2'] = True
SOURCES += ['pixman-sse2.c']
SOURCES['pixman-sse2.c'].flags += CONFIG['SSE_FLAGS'] + CONFIG['SSE2_FLAGS']
if CONFIG['GNU_CC']:
SOURCES['pixman-sse2.c'].flags += ['-Winline']
if use_vmx:
DEFINES['USE_VMX'] = True
SOURCES += ['pixman-vmx.c']
SOURCES['pixman-vmx.c'].flags += ['-maltivec']
if use_arm_simd_gcc:
DEFINES['USE_ARM_SIMD'] = True
SOURCES += ['pixman-arm-simd.c']
if use_arm_neon_gcc:
DEFINES['USE_ARM_NEON'] = True
SOURCES += ['pixman-arm-neon.c']
SOURCES['pixman-arm-neon.c'].flags += CONFIG['NEON_FLAGS']
# Suppress warnings in third-party code.
if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
CFLAGS += [
'-Wno-address',
'-Wno-missing-field-initializers',
'-Wno-sign-compare',
'-Wno-unused', # too many unused warnings; ignore
]
if CONFIG['CLANG_CXX'] or CONFIG['CLANG_CL']:
CFLAGS += [
'-Wno-incompatible-pointer-types',
'-Wno-tautological-compare',
'-Wno-tautological-constant-out-of-range-compare',
]
if CONFIG['CLANG_CL']:
CFLAGS += [
'-Wno-unused-variable',
]
# See bug 386897.
if CONFIG['OS_TARGET'] == 'Android' and CONFIG['MOZ_OPTIMIZE']:
CFLAGS += ['-O2']

View file

@ -0,0 +1,3 @@
#define PIXMAN_FB_ACCESSORS
#include "pixman-access.c"

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,25 @@
#ifdef PIXMAN_FB_ACCESSORS
#define READ(img, ptr) \
(((bits_image_t *)(img))->read_func ((ptr), sizeof(*(ptr))))
#define WRITE(img, ptr,val) \
(((bits_image_t *)(img))->write_func ((ptr), (val), sizeof (*(ptr))))
#define MEMSET_WRAPPED(img, dst, val, size) \
do { \
size_t _i; \
uint8_t *_dst = (uint8_t*)(dst); \
for(_i = 0; _i < (size_t) size; _i++) { \
WRITE((img), _dst +_i, (val)); \
} \
} while (0)
#else
#define READ(img, ptr) (*(ptr))
#define WRITE(img, ptr, val) (*(ptr) = (val))
#define MEMSET_WRAPPED(img, dst, val, size) \
memset(dst, val, size)
#endif

View file

@ -0,0 +1,428 @@
/*
* Copyright © 2010 Nokia Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Siarhei Siamashka (siarhei.siamashka@nokia.com)
*/
#ifndef PIXMAN_ARM_COMMON_H
#define PIXMAN_ARM_COMMON_H
#include "pixman-inlines.h"
/* Define some macros which can expand into proxy functions between
* ARM assembly optimized functions and the rest of pixman fast path API.
*
* All the low level ARM assembly functions have to use ARM EABI
* calling convention and take up to 8 arguments:
* width, height, dst, dst_stride, src, src_stride, mask, mask_stride
*
* The arguments are ordered with the most important coming first (the
* first 4 arguments are passed to function in registers, the rest are
* on stack). The last arguments are optional, for example if the
* function is not using mask, then 'mask' and 'mask_stride' can be
* omitted when doing a function call.
*
* Arguments 'src' and 'mask' contain either a pointer to the top left
* pixel of the composited rectangle or a pixel color value depending
* on the function type. In the case of just a color value (solid source
* or mask), the corresponding stride argument is unused.
*/
#define SKIP_ZERO_SRC 1
#define SKIP_ZERO_MASK 2
#define PIXMAN_ARM_BIND_FAST_PATH_SRC_DST(cputype, name, \
src_type, src_cnt, \
dst_type, dst_cnt) \
void \
pixman_composite_##name##_asm_##cputype (int32_t w, \
int32_t h, \
dst_type *dst, \
int32_t dst_stride, \
src_type *src, \
int32_t src_stride); \
\
static void \
cputype##_composite_##name (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
dst_type *dst_line; \
src_type *src_line; \
int32_t dst_stride, src_stride; \
\
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, src_type, \
src_stride, src_line, src_cnt); \
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type, \
dst_stride, dst_line, dst_cnt); \
\
pixman_composite_##name##_asm_##cputype (width, height, \
dst_line, dst_stride, \
src_line, src_stride); \
}
#define PIXMAN_ARM_BIND_FAST_PATH_N_DST(flags, cputype, name, \
dst_type, dst_cnt) \
void \
pixman_composite_##name##_asm_##cputype (int32_t w, \
int32_t h, \
dst_type *dst, \
int32_t dst_stride, \
uint32_t src); \
\
static void \
cputype##_composite_##name (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
dst_type *dst_line; \
int32_t dst_stride; \
uint32_t src; \
\
src = _pixman_image_get_solid ( \
imp, src_image, dest_image->bits.format); \
\
if ((flags & SKIP_ZERO_SRC) && src == 0) \
return; \
\
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type, \
dst_stride, dst_line, dst_cnt); \
\
pixman_composite_##name##_asm_##cputype (width, height, \
dst_line, dst_stride, \
src); \
}
#define PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST(flags, cputype, name, \
mask_type, mask_cnt, \
dst_type, dst_cnt) \
void \
pixman_composite_##name##_asm_##cputype (int32_t w, \
int32_t h, \
dst_type *dst, \
int32_t dst_stride, \
uint32_t src, \
int32_t unused, \
mask_type *mask, \
int32_t mask_stride); \
\
static void \
cputype##_composite_##name (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
dst_type *dst_line; \
mask_type *mask_line; \
int32_t dst_stride, mask_stride; \
uint32_t src; \
\
src = _pixman_image_get_solid ( \
imp, src_image, dest_image->bits.format); \
\
if ((flags & SKIP_ZERO_SRC) && src == 0) \
return; \
\
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type, \
dst_stride, dst_line, dst_cnt); \
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, mask_type, \
mask_stride, mask_line, mask_cnt); \
\
pixman_composite_##name##_asm_##cputype (width, height, \
dst_line, dst_stride, \
src, 0, \
mask_line, mask_stride); \
}
#define PIXMAN_ARM_BIND_FAST_PATH_SRC_N_DST(flags, cputype, name, \
src_type, src_cnt, \
dst_type, dst_cnt) \
void \
pixman_composite_##name##_asm_##cputype (int32_t w, \
int32_t h, \
dst_type *dst, \
int32_t dst_stride, \
src_type *src, \
int32_t src_stride, \
uint32_t mask); \
\
static void \
cputype##_composite_##name (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
dst_type *dst_line; \
src_type *src_line; \
int32_t dst_stride, src_stride; \
uint32_t mask; \
\
mask = _pixman_image_get_solid ( \
imp, mask_image, dest_image->bits.format); \
\
if ((flags & SKIP_ZERO_MASK) && mask == 0) \
return; \
\
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type, \
dst_stride, dst_line, dst_cnt); \
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, src_type, \
src_stride, src_line, src_cnt); \
\
pixman_composite_##name##_asm_##cputype (width, height, \
dst_line, dst_stride, \
src_line, src_stride, \
mask); \
}
#define PIXMAN_ARM_BIND_FAST_PATH_SRC_MASK_DST(cputype, name, \
src_type, src_cnt, \
mask_type, mask_cnt, \
dst_type, dst_cnt) \
void \
pixman_composite_##name##_asm_##cputype (int32_t w, \
int32_t h, \
dst_type *dst, \
int32_t dst_stride, \
src_type *src, \
int32_t src_stride, \
mask_type *mask, \
int32_t mask_stride); \
\
static void \
cputype##_composite_##name (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
dst_type *dst_line; \
src_type *src_line; \
mask_type *mask_line; \
int32_t dst_stride, src_stride, mask_stride; \
\
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type, \
dst_stride, dst_line, dst_cnt); \
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, src_type, \
src_stride, src_line, src_cnt); \
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, mask_type, \
mask_stride, mask_line, mask_cnt); \
\
pixman_composite_##name##_asm_##cputype (width, height, \
dst_line, dst_stride, \
src_line, src_stride, \
mask_line, mask_stride); \
}
#define PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_DST(cputype, name, op, \
src_type, dst_type) \
void \
pixman_scaled_nearest_scanline_##name##_##op##_asm_##cputype ( \
int32_t w, \
dst_type * dst, \
const src_type * src, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x, \
pixman_fixed_t max_vx); \
\
static force_inline void \
scaled_nearest_scanline_##cputype##_##name##_##op (dst_type * pd, \
const src_type * ps, \
int32_t w, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x, \
pixman_fixed_t max_vx, \
pixman_bool_t zero_src) \
{ \
pixman_scaled_nearest_scanline_##name##_##op##_asm_##cputype (w, pd, ps, \
vx, unit_x, \
max_vx); \
} \
\
FAST_NEAREST_MAINLOOP (cputype##_##name##_cover_##op, \
scaled_nearest_scanline_##cputype##_##name##_##op, \
src_type, dst_type, COVER) \
FAST_NEAREST_MAINLOOP (cputype##_##name##_none_##op, \
scaled_nearest_scanline_##cputype##_##name##_##op, \
src_type, dst_type, NONE) \
FAST_NEAREST_MAINLOOP (cputype##_##name##_pad_##op, \
scaled_nearest_scanline_##cputype##_##name##_##op, \
src_type, dst_type, PAD) \
FAST_NEAREST_MAINLOOP (cputype##_##name##_normal_##op, \
scaled_nearest_scanline_##cputype##_##name##_##op, \
src_type, dst_type, NORMAL)
/* Provide entries for the fast path table */
#define PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH(op,s,d,func) \
SIMPLE_NEAREST_FAST_PATH_COVER (op,s,d,func), \
SIMPLE_NEAREST_FAST_PATH_NONE (op,s,d,func), \
SIMPLE_NEAREST_FAST_PATH_PAD (op,s,d,func), \
SIMPLE_NEAREST_FAST_PATH_NORMAL (op,s,d,func)
#define PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_A8_DST(flags, cputype, name, op, \
src_type, dst_type) \
void \
pixman_scaled_nearest_scanline_##name##_##op##_asm_##cputype ( \
int32_t w, \
dst_type * dst, \
const src_type * src, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x, \
pixman_fixed_t max_vx, \
const uint8_t * mask); \
\
static force_inline void \
scaled_nearest_scanline_##cputype##_##name##_##op (const uint8_t * mask, \
dst_type * pd, \
const src_type * ps, \
int32_t w, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x, \
pixman_fixed_t max_vx, \
pixman_bool_t zero_src) \
{ \
if ((flags & SKIP_ZERO_SRC) && zero_src) \
return; \
pixman_scaled_nearest_scanline_##name##_##op##_asm_##cputype (w, pd, ps, \
vx, unit_x, \
max_vx, \
mask); \
} \
\
FAST_NEAREST_MAINLOOP_COMMON (cputype##_##name##_cover_##op, \
scaled_nearest_scanline_##cputype##_##name##_##op,\
src_type, uint8_t, dst_type, COVER, TRUE, FALSE)\
FAST_NEAREST_MAINLOOP_COMMON (cputype##_##name##_none_##op, \
scaled_nearest_scanline_##cputype##_##name##_##op,\
src_type, uint8_t, dst_type, NONE, TRUE, FALSE) \
FAST_NEAREST_MAINLOOP_COMMON (cputype##_##name##_pad_##op, \
scaled_nearest_scanline_##cputype##_##name##_##op,\
src_type, uint8_t, dst_type, PAD, TRUE, FALSE) \
FAST_NEAREST_MAINLOOP_COMMON (cputype##_##name##_normal_##op, \
scaled_nearest_scanline_##cputype##_##name##_##op,\
src_type, uint8_t, dst_type, NORMAL, TRUE, FALSE)
/* Provide entries for the fast path table */
#define PIXMAN_ARM_SIMPLE_NEAREST_A8_MASK_FAST_PATH(op,s,d,func) \
SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER (op,s,d,func), \
SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE (op,s,d,func), \
SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD (op,s,d,func), \
SIMPLE_NEAREST_A8_MASK_FAST_PATH_NORMAL (op,s,d,func)
/*****************************************************************************/
#define PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST(flags, cputype, name, op, \
src_type, dst_type) \
void \
pixman_scaled_bilinear_scanline_##name##_##op##_asm_##cputype ( \
dst_type * dst, \
const src_type * top, \
const src_type * bottom, \
int wt, \
int wb, \
pixman_fixed_t x, \
pixman_fixed_t ux, \
int width); \
\
static force_inline void \
scaled_bilinear_scanline_##cputype##_##name##_##op ( \
dst_type * dst, \
const uint32_t * mask, \
const src_type * src_top, \
const src_type * src_bottom, \
int32_t w, \
int wt, \
int wb, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x, \
pixman_fixed_t max_vx, \
pixman_bool_t zero_src) \
{ \
if ((flags & SKIP_ZERO_SRC) && zero_src) \
return; \
pixman_scaled_bilinear_scanline_##name##_##op##_asm_##cputype ( \
dst, src_top, src_bottom, wt, wb, vx, unit_x, w); \
} \
\
FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_cover_##op, \
scaled_bilinear_scanline_##cputype##_##name##_##op, \
NULL, src_type, uint32_t, dst_type, COVER, FLAG_NONE) \
FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_none_##op, \
scaled_bilinear_scanline_##cputype##_##name##_##op, \
NULL, src_type, uint32_t, dst_type, NONE, FLAG_NONE) \
FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_pad_##op, \
scaled_bilinear_scanline_##cputype##_##name##_##op, \
NULL, src_type, uint32_t, dst_type, PAD, FLAG_NONE) \
FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_normal_##op, \
scaled_bilinear_scanline_##cputype##_##name##_##op, \
NULL, src_type, uint32_t, dst_type, NORMAL, \
FLAG_NONE)
#define PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_A8_DST(flags, cputype, name, op, \
src_type, dst_type) \
void \
pixman_scaled_bilinear_scanline_##name##_##op##_asm_##cputype ( \
dst_type * dst, \
const uint8_t * mask, \
const src_type * top, \
const src_type * bottom, \
int wt, \
int wb, \
pixman_fixed_t x, \
pixman_fixed_t ux, \
int width); \
\
static force_inline void \
scaled_bilinear_scanline_##cputype##_##name##_##op ( \
dst_type * dst, \
const uint8_t * mask, \
const src_type * src_top, \
const src_type * src_bottom, \
int32_t w, \
int wt, \
int wb, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x, \
pixman_fixed_t max_vx, \
pixman_bool_t zero_src) \
{ \
if ((flags & SKIP_ZERO_SRC) && zero_src) \
return; \
pixman_scaled_bilinear_scanline_##name##_##op##_asm_##cputype ( \
dst, mask, src_top, src_bottom, wt, wb, vx, unit_x, w); \
} \
\
FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_cover_##op, \
scaled_bilinear_scanline_##cputype##_##name##_##op, \
NULL, src_type, uint8_t, dst_type, COVER, \
FLAG_HAVE_NON_SOLID_MASK) \
FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_none_##op, \
scaled_bilinear_scanline_##cputype##_##name##_##op, \
NULL, src_type, uint8_t, dst_type, NONE, \
FLAG_HAVE_NON_SOLID_MASK) \
FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_pad_##op, \
scaled_bilinear_scanline_##cputype##_##name##_##op, \
NULL, src_type, uint8_t, dst_type, PAD, \
FLAG_HAVE_NON_SOLID_MASK) \
FAST_BILINEAR_MAINLOOP_COMMON (cputype##_##name##_normal_##op, \
scaled_bilinear_scanline_##cputype##_##name##_##op, \
NULL, src_type, uint8_t, dst_type, NORMAL, \
FLAG_HAVE_NON_SOLID_MASK)
#endif

View file

@ -0,0 +1,21 @@
area pixman_msvc, code, readonly
export pixman_msvc_try_arm_simd_op
pixman_msvc_try_arm_simd_op
;; I don't think the msvc arm asm knows how to do SIMD insns
;; uqadd8 r3,r3,r3
dcd 0xe6633f93
mov pc,lr
endp
export pixman_msvc_try_arm_neon_op
pixman_msvc_try_arm_neon_op
;; I don't think the msvc arm asm knows how to do NEON insns
;; veor d0,d0,d0
dcd 0xf3000110
mov pc,lr
endp
end

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,513 @@
/*
* Copyright © 2009 ARM Ltd, Movial Creative Technologies Oy
*
* 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 ARM Ltd not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. ARM Ltd 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.
*
* Author: Ian Rickards (ian.rickards@arm.com)
* Author: Jonathan Morton (jonathan.morton@movial.com)
* Author: Markku Vire (markku.vire@movial.com)
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include "pixman-private.h"
#include "pixman-arm-common.h"
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, src_8888_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, src_x888_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, src_0565_0565,
uint16_t, 1, uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, src_0888_0888,
uint8_t, 3, uint8_t, 3)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, src_8888_0565,
uint32_t, 1, uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, src_0565_8888,
uint16_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, src_0888_8888_rev,
uint8_t, 3, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, src_0888_0565_rev,
uint8_t, 3, uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, src_pixbuf_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, src_rpixbuf_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, add_8_8,
uint8_t, 1, uint8_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, add_8888_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, over_8888_0565,
uint32_t, 1, uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, over_8888_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, out_reverse_8_0565,
uint8_t, 1, uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (neon, out_reverse_8_8888,
uint8_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_DST (SKIP_ZERO_SRC, neon, over_n_0565,
uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_DST (SKIP_ZERO_SRC, neon, over_n_8888,
uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_DST (SKIP_ZERO_SRC, neon, over_reverse_n_8888,
uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_DST (0, neon, in_n_8,
uint8_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, neon, over_n_8_0565,
uint8_t, 1, uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, neon, over_n_8_8888,
uint8_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, neon, over_n_8888_8888_ca,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, neon, over_n_8888_0565_ca,
uint32_t, 1, uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, neon, over_n_8_8,
uint8_t, 1, uint8_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, neon, add_n_8_8,
uint8_t, 1, uint8_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, neon, add_n_8_8888,
uint8_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (0, neon, src_n_8_8888,
uint8_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (0, neon, src_n_8_8,
uint8_t, 1, uint8_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, neon, over_8888_n_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, neon, over_8888_n_0565,
uint32_t, 1, uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, neon, over_0565_n_0565,
uint16_t, 1, uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, neon, add_8888_n_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_MASK_DST (neon, add_8_8_8,
uint8_t, 1, uint8_t, 1, uint8_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_MASK_DST (neon, add_0565_8_0565,
uint16_t, 1, uint8_t, 1, uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_MASK_DST (neon, add_8888_8_8888,
uint32_t, 1, uint8_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_MASK_DST (neon, add_8888_8888_8888,
uint32_t, 1, uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_MASK_DST (neon, over_8888_8_8888,
uint32_t, 1, uint8_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_MASK_DST (neon, over_8888_8888_8888,
uint32_t, 1, uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_MASK_DST (neon, over_8888_8_0565,
uint32_t, 1, uint8_t, 1, uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_MASK_DST (neon, over_0565_8_0565,
uint16_t, 1, uint8_t, 1, uint16_t, 1)
PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_DST (neon, 8888_8888, OVER,
uint32_t, uint32_t)
PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_DST (neon, 8888_0565, OVER,
uint32_t, uint16_t)
PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_DST (neon, 8888_0565, SRC,
uint32_t, uint16_t)
PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_DST (neon, 0565_8888, SRC,
uint16_t, uint32_t)
PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_A8_DST (SKIP_ZERO_SRC, neon, 8888_8_0565,
OVER, uint32_t, uint16_t)
PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_A8_DST (SKIP_ZERO_SRC, neon, 0565_8_0565,
OVER, uint16_t, uint16_t)
PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (0, neon, 8888_8888, SRC,
uint32_t, uint32_t)
PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (0, neon, 8888_0565, SRC,
uint32_t, uint16_t)
PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (0, neon, 0565_x888, SRC,
uint16_t, uint32_t)
PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (0, neon, 0565_0565, SRC,
uint16_t, uint16_t)
PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (SKIP_ZERO_SRC, neon, 8888_8888, OVER,
uint32_t, uint32_t)
static force_inline void
pixman_scaled_bilinear_scanline_8888_8888_SRC (
uint32_t * dst,
const uint32_t * mask,
const uint32_t * src_top,
const uint32_t * src_bottom,
int32_t w,
int wt,
int wb,
pixman_fixed_t vx,
pixman_fixed_t unit_x,
pixman_fixed_t max_vx,
pixman_bool_t zero_src)
{
pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon (dst, src_top, src_bottom, wt, wb, vx, unit_x, w);
}
PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_DST (SKIP_ZERO_SRC, neon, 8888_8888, ADD,
uint32_t, uint32_t)
PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_A8_DST (0, neon, 8888_8_8888, SRC,
uint32_t, uint32_t)
PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_A8_DST (0, neon, 8888_8_0565, SRC,
uint32_t, uint16_t)
PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_A8_DST (0, neon, 0565_8_x888, SRC,
uint16_t, uint32_t)
PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_A8_DST (0, neon, 0565_8_0565, SRC,
uint16_t, uint16_t)
PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_A8_DST (SKIP_ZERO_SRC, neon, 8888_8_8888, OVER,
uint32_t, uint32_t)
PIXMAN_ARM_BIND_SCALED_BILINEAR_SRC_A8_DST (SKIP_ZERO_SRC, neon, 8888_8_8888, ADD,
uint32_t, uint32_t)
void
pixman_composite_src_n_8_asm_neon (int32_t w,
int32_t h,
uint8_t *dst,
int32_t dst_stride,
uint8_t src);
void
pixman_composite_src_n_0565_asm_neon (int32_t w,
int32_t h,
uint16_t *dst,
int32_t dst_stride,
uint16_t src);
void
pixman_composite_src_n_8888_asm_neon (int32_t w,
int32_t h,
uint32_t *dst,
int32_t dst_stride,
uint32_t src);
static pixman_bool_t
arm_neon_fill (pixman_implementation_t *imp,
uint32_t * bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t _xor)
{
/* stride is always multiple of 32bit units in pixman */
uint32_t byte_stride = stride * sizeof(uint32_t);
switch (bpp)
{
case 8:
pixman_composite_src_n_8_asm_neon (
width,
height,
(uint8_t *)(((char *) bits) + y * byte_stride + x),
byte_stride,
_xor & 0xff);
return TRUE;
case 16:
pixman_composite_src_n_0565_asm_neon (
width,
height,
(uint16_t *)(((char *) bits) + y * byte_stride + x * 2),
byte_stride / 2,
_xor & 0xffff);
return TRUE;
case 32:
pixman_composite_src_n_8888_asm_neon (
width,
height,
(uint32_t *)(((char *) bits) + y * byte_stride + x * 4),
byte_stride / 4,
_xor);
return TRUE;
default:
return FALSE;
}
}
static pixman_bool_t
arm_neon_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 dest_x,
int dest_y,
int width,
int height)
{
if (src_bpp != dst_bpp)
return FALSE;
switch (src_bpp)
{
case 16:
pixman_composite_src_0565_0565_asm_neon (
width, height,
(uint16_t *)(((char *) dst_bits) +
dest_y * dst_stride * 4 + dest_x * 2), dst_stride * 2,
(uint16_t *)(((char *) src_bits) +
src_y * src_stride * 4 + src_x * 2), src_stride * 2);
return TRUE;
case 32:
pixman_composite_src_8888_8888_asm_neon (
width, height,
(uint32_t *)(((char *) dst_bits) +
dest_y * dst_stride * 4 + dest_x * 4), dst_stride,
(uint32_t *)(((char *) src_bits) +
src_y * src_stride * 4 + src_x * 4), src_stride);
return TRUE;
default:
return FALSE;
}
}
static inline void op_bilinear_over_8888_0565(uint16_t *dst, const uint32_t *mask, const uint32_t *src, int width)
{
pixman_composite_over_8888_0565_asm_neon (width, 1, dst, 0, src, 0);
}
FAST_BILINEAR_MAINLOOP_COMMON (neon_8888_0565_cover_OVER,
pixman_scaled_bilinear_scanline_8888_8888_SRC, op_bilinear_over_8888_0565,
uint32_t, uint32_t, uint16_t,
COVER, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (neon_8888_0565_pad_OVER,
pixman_scaled_bilinear_scanline_8888_8888_SRC, op_bilinear_over_8888_0565,
uint32_t, uint32_t, uint16_t,
PAD, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (neon_8888_0565_none_OVER,
pixman_scaled_bilinear_scanline_8888_8888_SRC, op_bilinear_over_8888_0565,
uint32_t, uint32_t, uint16_t,
NONE, FLAG_NONE)
FAST_BILINEAR_MAINLOOP_COMMON (neon_8888_0565_normal_OVER,
pixman_scaled_bilinear_scanline_8888_8888_SRC, op_bilinear_over_8888_0565,
uint32_t, uint32_t, uint16_t,
NORMAL, FLAG_NONE)
static const pixman_fast_path_t arm_neon_fast_paths[] =
{
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, r5g6b5, neon_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, b5g6r5, neon_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, r5g6b5, neon_composite_src_8888_0565),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, r5g6b5, neon_composite_src_8888_0565),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, b5g6r5, neon_composite_src_8888_0565),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, b5g6r5, neon_composite_src_8888_0565),
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, a8r8g8b8, neon_composite_src_0565_8888),
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, x8r8g8b8, neon_composite_src_0565_8888),
PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, a8b8g8r8, neon_composite_src_0565_8888),
PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, x8b8g8r8, neon_composite_src_0565_8888),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, x8r8g8b8, neon_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, x8r8g8b8, neon_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, x8b8g8r8, neon_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, x8b8g8r8, neon_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, a8r8g8b8, neon_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, a8b8g8r8, neon_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, a8r8g8b8, neon_composite_src_x888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, a8b8g8r8, neon_composite_src_x888_8888),
PIXMAN_STD_FAST_PATH (SRC, r8g8b8, null, r8g8b8, neon_composite_src_0888_0888),
PIXMAN_STD_FAST_PATH (SRC, b8g8r8, null, x8r8g8b8, neon_composite_src_0888_8888_rev),
PIXMAN_STD_FAST_PATH (SRC, b8g8r8, null, r5g6b5, neon_composite_src_0888_0565_rev),
PIXMAN_STD_FAST_PATH (SRC, pixbuf, pixbuf, a8r8g8b8, neon_composite_src_pixbuf_8888),
PIXMAN_STD_FAST_PATH (SRC, pixbuf, pixbuf, a8b8g8r8, neon_composite_src_rpixbuf_8888),
PIXMAN_STD_FAST_PATH (SRC, rpixbuf, rpixbuf, a8r8g8b8, neon_composite_src_rpixbuf_8888),
PIXMAN_STD_FAST_PATH (SRC, rpixbuf, rpixbuf, a8b8g8r8, neon_composite_src_pixbuf_8888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, a8r8g8b8, neon_composite_src_n_8_8888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, x8r8g8b8, neon_composite_src_n_8_8888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, a8b8g8r8, neon_composite_src_n_8_8888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, x8b8g8r8, neon_composite_src_n_8_8888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, a8, neon_composite_src_n_8_8),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8, neon_composite_over_n_8_8),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, r5g6b5, neon_composite_over_n_8_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, b5g6r5, neon_composite_over_n_8_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8r8g8b8, neon_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8r8g8b8, neon_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8b8g8r8, neon_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8b8g8r8, neon_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, null, r5g6b5, neon_composite_over_n_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, null, a8r8g8b8, neon_composite_over_n_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, null, x8r8g8b8, neon_composite_over_n_8888),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, a8r8g8b8, neon_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, x8r8g8b8, neon_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, a8b8g8r8, neon_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, x8b8g8r8, neon_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, r5g6b5, neon_composite_over_n_8888_0565_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, b5g6r5, neon_composite_over_n_8888_0565_ca),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, a8r8g8b8, neon_composite_over_8888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, x8r8g8b8, neon_composite_over_8888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, r5g6b5, neon_composite_over_8888_n_0565),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, b5g6r5, neon_composite_over_8888_n_0565),
PIXMAN_STD_FAST_PATH (OVER, r5g6b5, solid, r5g6b5, neon_composite_over_0565_n_0565),
PIXMAN_STD_FAST_PATH (OVER, b5g6r5, solid, b5g6r5, neon_composite_over_0565_n_0565),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8, a8r8g8b8, neon_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8, x8r8g8b8, neon_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, a8, a8b8g8r8, neon_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, a8, x8b8g8r8, neon_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8, r5g6b5, neon_composite_over_8888_8_0565),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, a8, b5g6r5, neon_composite_over_8888_8_0565),
PIXMAN_STD_FAST_PATH (OVER, r5g6b5, a8, r5g6b5, neon_composite_over_0565_8_0565),
PIXMAN_STD_FAST_PATH (OVER, b5g6r5, a8, b5g6r5, neon_composite_over_0565_8_0565),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, a8r8g8b8, neon_composite_over_8888_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, r5g6b5, neon_composite_over_8888_0565),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, b5g6r5, neon_composite_over_8888_0565),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, a8r8g8b8, neon_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, x8r8g8b8, neon_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, a8b8g8r8, neon_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, x8b8g8r8, neon_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, x8r8g8b8, null, a8r8g8b8, neon_composite_src_x888_8888),
PIXMAN_STD_FAST_PATH (OVER, x8b8g8r8, null, a8b8g8r8, neon_composite_src_x888_8888),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8, neon_composite_add_n_8_8),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8r8g8b8, neon_composite_add_n_8_8888),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8b8g8r8, neon_composite_add_n_8_8888),
PIXMAN_STD_FAST_PATH (ADD, a8, a8, a8, neon_composite_add_8_8_8),
PIXMAN_STD_FAST_PATH (ADD, r5g6b5, a8, r5g6b5, neon_composite_add_0565_8_0565),
PIXMAN_STD_FAST_PATH (ADD, b5g6r5, a8, b5g6r5, neon_composite_add_0565_8_0565),
PIXMAN_STD_FAST_PATH (ADD, a8r8g8b8, a8, a8r8g8b8, neon_composite_add_8888_8_8888),
PIXMAN_STD_FAST_PATH (ADD, a8b8g8r8, a8, a8b8g8r8, neon_composite_add_8888_8_8888),
PIXMAN_STD_FAST_PATH (ADD, a8r8g8b8, a8r8g8b8, a8r8g8b8, neon_composite_add_8888_8888_8888),
PIXMAN_STD_FAST_PATH (ADD, a8r8g8b8, solid, a8r8g8b8, neon_composite_add_8888_n_8888),
PIXMAN_STD_FAST_PATH (ADD, a8b8g8r8, solid, a8b8g8r8, neon_composite_add_8888_n_8888),
PIXMAN_STD_FAST_PATH (ADD, a8, null, a8, neon_composite_add_8_8),
PIXMAN_STD_FAST_PATH (ADD, a8r8g8b8, null, a8r8g8b8, neon_composite_add_8888_8888),
PIXMAN_STD_FAST_PATH (ADD, a8b8g8r8, null, a8b8g8r8, neon_composite_add_8888_8888),
PIXMAN_STD_FAST_PATH (IN, solid, null, a8, neon_composite_in_n_8),
PIXMAN_STD_FAST_PATH (OVER_REVERSE, solid, null, a8r8g8b8, neon_composite_over_reverse_n_8888),
PIXMAN_STD_FAST_PATH (OVER_REVERSE, solid, null, a8b8g8r8, neon_composite_over_reverse_n_8888),
PIXMAN_STD_FAST_PATH (OUT_REVERSE, a8, null, r5g6b5, neon_composite_out_reverse_8_0565),
PIXMAN_STD_FAST_PATH (OUT_REVERSE, a8, null, b5g6r5, neon_composite_out_reverse_8_0565),
PIXMAN_STD_FAST_PATH (OUT_REVERSE, a8, null, a8r8g8b8, neon_composite_out_reverse_8_8888),
PIXMAN_STD_FAST_PATH (OUT_REVERSE, a8, null, a8b8g8r8, neon_composite_out_reverse_8_8888),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, neon_8888_8888),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, neon_8888_8888),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, neon_8888_8888),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, neon_8888_8888),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (OVER, a8r8g8b8, r5g6b5, neon_8888_0565),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (OVER, a8b8g8r8, b5g6r5, neon_8888_0565),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, r5g6b5, neon_8888_0565),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, x8r8g8b8, r5g6b5, neon_8888_0565),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, b5g6r5, neon_8888_0565),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, x8b8g8r8, b5g6r5, neon_8888_0565),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, b5g6r5, x8b8g8r8, neon_0565_8888),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, r5g6b5, x8r8g8b8, neon_0565_8888),
/* Note: NONE repeat is not supported yet */
SIMPLE_NEAREST_FAST_PATH_COVER (SRC, r5g6b5, a8r8g8b8, neon_0565_8888),
SIMPLE_NEAREST_FAST_PATH_COVER (SRC, b5g6r5, a8b8g8r8, neon_0565_8888),
SIMPLE_NEAREST_FAST_PATH_PAD (SRC, r5g6b5, a8r8g8b8, neon_0565_8888),
SIMPLE_NEAREST_FAST_PATH_PAD (SRC, b5g6r5, a8b8g8r8, neon_0565_8888),
PIXMAN_ARM_SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, a8r8g8b8, r5g6b5, neon_8888_8_0565),
PIXMAN_ARM_SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, a8b8g8r8, b5g6r5, neon_8888_8_0565),
PIXMAN_ARM_SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, r5g6b5, r5g6b5, neon_0565_8_0565),
PIXMAN_ARM_SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, b5g6r5, b5g6r5, neon_0565_8_0565),
SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, neon_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, neon_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, neon_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, r5g6b5, neon_8888_0565),
SIMPLE_BILINEAR_FAST_PATH (SRC, x8r8g8b8, r5g6b5, neon_8888_0565),
SIMPLE_BILINEAR_FAST_PATH (SRC, r5g6b5, x8r8g8b8, neon_0565_x888),
SIMPLE_BILINEAR_FAST_PATH (SRC, r5g6b5, r5g6b5, neon_0565_0565),
SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, neon_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, neon_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (ADD, a8r8g8b8, a8r8g8b8, neon_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (ADD, a8r8g8b8, x8r8g8b8, neon_8888_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, neon_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, neon_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, neon_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, a8r8g8b8, r5g6b5, neon_8888_8_0565),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, x8r8g8b8, r5g6b5, neon_8888_8_0565),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, r5g6b5, x8r8g8b8, neon_0565_8_x888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, r5g6b5, r5g6b5, neon_0565_8_0565),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, neon_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, neon_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (ADD, a8r8g8b8, a8r8g8b8, neon_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (ADD, a8r8g8b8, x8r8g8b8, neon_8888_8_8888),
SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, r5g6b5, neon_8888_0565),
{ PIXMAN_OP_NONE },
};
#define BIND_COMBINE_U(name) \
void \
pixman_composite_scanline_##name##_mask_asm_neon (int32_t w, \
const uint32_t *dst, \
const uint32_t *src, \
const uint32_t *mask); \
\
void \
pixman_composite_scanline_##name##_asm_neon (int32_t w, \
const uint32_t *dst, \
const uint32_t *src); \
\
static void \
neon_combine_##name##_u (pixman_implementation_t *imp, \
pixman_op_t op, \
uint32_t * dest, \
const uint32_t * src, \
const uint32_t * mask, \
int width) \
{ \
if (mask) \
pixman_composite_scanline_##name##_mask_asm_neon (width, dest, \
src, mask); \
else \
pixman_composite_scanline_##name##_asm_neon (width, dest, src); \
}
BIND_COMBINE_U (over)
BIND_COMBINE_U (add)
BIND_COMBINE_U (out_reverse)
pixman_implementation_t *
_pixman_implementation_create_arm_neon (pixman_implementation_t *fallback)
{
pixman_implementation_t *imp =
_pixman_implementation_create (fallback, arm_neon_fast_paths);
imp->combine_32[PIXMAN_OP_OVER] = neon_combine_over_u;
imp->combine_32[PIXMAN_OP_ADD] = neon_combine_add_u;
imp->combine_32[PIXMAN_OP_OUT_REVERSE] = neon_combine_out_reverse_u;
imp->blt = arm_neon_blt;
imp->fill = arm_neon_fill;
return imp;
}

View file

@ -0,0 +1,165 @@
/*
* Copyright © 2008 Mozilla Corporation
* Copyright © 2010 Nokia 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 Mozilla Corporation not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Mozilla Corporation 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.
*
* Author: Jeff Muizelaar (jeff@infidigm.net)
*
*/
/* Prevent the stack from becoming executable */
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
.text
.arch armv6
.object_arch armv4
.arm
.altmacro
.p2align 2
/* Supplementary macro for setting function attributes */
.macro pixman_asm_function fname
.func fname
.global fname
#ifdef __ELF__
.hidden fname
.type fname, %function
#endif
fname:
.endm
/*
* Note: This code is only using armv5te instructions (not even armv6),
* but is scheduled for ARM Cortex-A8 pipeline. So it might need to
* be split into a few variants, tuned for each microarchitecture.
*
* TODO: In order to get good performance on ARM9/ARM11 cores (which don't
* have efficient write combining), it needs to be changed to use 16-byte
* aligned writes using STM instruction.
*
* Nearest scanline scaler macro template uses the following arguments:
* fname - name of the function to generate
* bpp_shift - (1 << bpp_shift) is the size of pixel in bytes
* t - type suffix for LDR/STR instructions
* prefetch_distance - prefetch in the source image by that many
* pixels ahead
* prefetch_braking_distance - stop prefetching when that many pixels are
* remaining before the end of scanline
*/
.macro generate_nearest_scanline_func fname, bpp_shift, t, \
prefetch_distance, \
prefetch_braking_distance
pixman_asm_function fname
W .req r0
DST .req r1
SRC .req r2
VX .req r3
UNIT_X .req ip
TMP1 .req r4
TMP2 .req r5
VXMASK .req r6
PF_OFFS .req r7
SRC_WIDTH_FIXED .req r8
ldr UNIT_X, [sp]
push {r4, r5, r6, r7, r8, r10}
mvn VXMASK, #((1 << bpp_shift) - 1)
ldr SRC_WIDTH_FIXED, [sp, #28]
/* define helper macro */
.macro scale_2_pixels
ldr&t TMP1, [SRC, TMP1]
and TMP2, VXMASK, VX, asr #(16 - bpp_shift)
adds VX, VX, UNIT_X
str&t TMP1, [DST], #(1 << bpp_shift)
9: subpls VX, VX, SRC_WIDTH_FIXED
bpl 9b
ldr&t TMP2, [SRC, TMP2]
and TMP1, VXMASK, VX, asr #(16 - bpp_shift)
adds VX, VX, UNIT_X
str&t TMP2, [DST], #(1 << bpp_shift)
9: subpls VX, VX, SRC_WIDTH_FIXED
bpl 9b
.endm
/* now do the scaling */
and TMP1, VXMASK, VX, asr #(16 - bpp_shift)
adds VX, VX, UNIT_X
9: subpls VX, VX, SRC_WIDTH_FIXED
bpl 9b
subs W, W, #(8 + prefetch_braking_distance)
blt 2f
/* calculate prefetch offset */
mov PF_OFFS, #prefetch_distance
mla PF_OFFS, UNIT_X, PF_OFFS, VX
1: /* main loop, process 8 pixels per iteration with prefetch */
pld [SRC, PF_OFFS, asr #(16 - bpp_shift)]
add PF_OFFS, UNIT_X, lsl #3
scale_2_pixels
scale_2_pixels
scale_2_pixels
scale_2_pixels
subs W, W, #8
bge 1b
2:
subs W, W, #(4 - 8 - prefetch_braking_distance)
blt 2f
1: /* process the remaining pixels */
scale_2_pixels
scale_2_pixels
subs W, W, #4
bge 1b
2:
tst W, #2
beq 2f
scale_2_pixels
2:
tst W, #1
ldrne&t TMP1, [SRC, TMP1]
strne&t TMP1, [DST]
/* cleanup helper macro */
.purgem scale_2_pixels
.unreq DST
.unreq SRC
.unreq W
.unreq VX
.unreq UNIT_X
.unreq TMP1
.unreq TMP2
.unreq VXMASK
.unreq PF_OFFS
.unreq SRC_WIDTH_FIXED
/* return */
pop {r4, r5, r6, r7, r8, r10}
bx lr
.endfunc
.endm
generate_nearest_scanline_func \
pixman_scaled_nearest_scanline_0565_0565_SRC_asm_armv6, 1, h, 80, 32
generate_nearest_scanline_func \
pixman_scaled_nearest_scanline_8888_8888_SRC_asm_armv6, 2, , 48, 32

View file

@ -0,0 +1,613 @@
/*
* Copyright © 2012 Raspberry Pi Foundation
* Copyright © 2012 RISC OS Open Ltd
*
* 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 the copyright holders not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. The copyright holders make 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.
*
* Author: Ben Avison (bavison@riscosopen.org)
*
*/
/* Prevent the stack from becoming executable */
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
.text
.arch armv6
.object_arch armv4
.arm
.altmacro
.p2align 2
#include "pixman-arm-simd-asm.h"
/* A head macro should do all processing which results in an output of up to
* 16 bytes, as far as the final load instruction. The corresponding tail macro
* should complete the processing of the up-to-16 bytes. The calling macro will
* sometimes choose to insert a preload or a decrement of X between them.
* cond ARM condition code for code block
* numbytes Number of output bytes that should be generated this time
* firstreg First WK register in which to place output
* unaligned_src Whether to use non-wordaligned loads of source image
* unaligned_mask Whether to use non-wordaligned loads of mask image
* preload If outputting 16 bytes causes 64 bytes to be read, whether an extra preload should be output
*/
.macro blit_init
line_saved_regs STRIDE_D, STRIDE_S
.endm
.macro blit_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload
pixld cond, numbytes, firstreg, SRC, unaligned_src
.endm
.macro blit_inner_loop process_head, process_tail, unaligned_src, unaligned_mask, dst_alignment
WK4 .req STRIDE_D
WK5 .req STRIDE_S
WK6 .req MASK
WK7 .req STRIDE_M
110: pixld , 16, 0, SRC, unaligned_src
pixld , 16, 4, SRC, unaligned_src
pld [SRC, SCRATCH]
pixst , 16, 0, DST
pixst , 16, 4, DST
subs X, X, #32*8/src_bpp
bhs 110b
.unreq WK4
.unreq WK5
.unreq WK6
.unreq WK7
.endm
generate_composite_function \
pixman_composite_src_8888_8888_asm_armv6, 32, 0, 32, \
FLAG_DST_WRITEONLY | FLAG_COND_EXEC | FLAG_SPILL_LINE_VARS_WIDE | FLAG_PROCESS_PRESERVES_SCRATCH, \
4, /* prefetch distance */ \
blit_init, \
nop_macro, /* newline */ \
nop_macro, /* cleanup */ \
blit_process_head, \
nop_macro, /* process tail */ \
blit_inner_loop
generate_composite_function \
pixman_composite_src_0565_0565_asm_armv6, 16, 0, 16, \
FLAG_DST_WRITEONLY | FLAG_COND_EXEC | FLAG_SPILL_LINE_VARS_WIDE | FLAG_PROCESS_PRESERVES_SCRATCH, \
4, /* prefetch distance */ \
blit_init, \
nop_macro, /* newline */ \
nop_macro, /* cleanup */ \
blit_process_head, \
nop_macro, /* process tail */ \
blit_inner_loop
generate_composite_function \
pixman_composite_src_8_8_asm_armv6, 8, 0, 8, \
FLAG_DST_WRITEONLY | FLAG_COND_EXEC | FLAG_SPILL_LINE_VARS_WIDE | FLAG_PROCESS_PRESERVES_SCRATCH, \
3, /* prefetch distance */ \
blit_init, \
nop_macro, /* newline */ \
nop_macro, /* cleanup */ \
blit_process_head, \
nop_macro, /* process tail */ \
blit_inner_loop
/******************************************************************************/
.macro src_n_8888_init
ldr SRC, [sp, #ARGS_STACK_OFFSET]
mov STRIDE_S, SRC
mov MASK, SRC
mov STRIDE_M, SRC
.endm
.macro src_n_0565_init
ldrh SRC, [sp, #ARGS_STACK_OFFSET]
orr SRC, SRC, lsl #16
mov STRIDE_S, SRC
mov MASK, SRC
mov STRIDE_M, SRC
.endm
.macro src_n_8_init
ldrb SRC, [sp, #ARGS_STACK_OFFSET]
orr SRC, SRC, lsl #8
orr SRC, SRC, lsl #16
mov STRIDE_S, SRC
mov MASK, SRC
mov STRIDE_M, SRC
.endm
.macro fill_process_tail cond, numbytes, firstreg
WK4 .req SRC
WK5 .req STRIDE_S
WK6 .req MASK
WK7 .req STRIDE_M
pixst cond, numbytes, 4, DST
.unreq WK4
.unreq WK5
.unreq WK6
.unreq WK7
.endm
generate_composite_function \
pixman_composite_src_n_8888_asm_armv6, 0, 0, 32, \
FLAG_DST_WRITEONLY | FLAG_COND_EXEC | FLAG_PROCESS_PRESERVES_PSR | FLAG_PROCESS_DOES_STORE | FLAG_PROCESS_PRESERVES_SCRATCH \
0, /* prefetch distance doesn't apply */ \
src_n_8888_init \
nop_macro, /* newline */ \
nop_macro /* cleanup */ \
nop_macro /* process head */ \
fill_process_tail
generate_composite_function \
pixman_composite_src_n_0565_asm_armv6, 0, 0, 16, \
FLAG_DST_WRITEONLY | FLAG_COND_EXEC | FLAG_PROCESS_PRESERVES_PSR | FLAG_PROCESS_DOES_STORE | FLAG_PROCESS_PRESERVES_SCRATCH \
0, /* prefetch distance doesn't apply */ \
src_n_0565_init \
nop_macro, /* newline */ \
nop_macro /* cleanup */ \
nop_macro /* process head */ \
fill_process_tail
generate_composite_function \
pixman_composite_src_n_8_asm_armv6, 0, 0, 8, \
FLAG_DST_WRITEONLY | FLAG_COND_EXEC | FLAG_PROCESS_PRESERVES_PSR | FLAG_PROCESS_DOES_STORE | FLAG_PROCESS_PRESERVES_SCRATCH \
0, /* prefetch distance doesn't apply */ \
src_n_8_init \
nop_macro, /* newline */ \
nop_macro /* cleanup */ \
nop_macro /* process head */ \
fill_process_tail
/******************************************************************************/
.macro src_x888_8888_pixel, cond, reg
orr&cond WK&reg, WK&reg, #0xFF000000
.endm
.macro pixman_composite_src_x888_8888_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload
pixld cond, numbytes, firstreg, SRC, unaligned_src
.endm
.macro pixman_composite_src_x888_8888_process_tail cond, numbytes, firstreg
src_x888_8888_pixel cond, %(firstreg+0)
.if numbytes >= 8
src_x888_8888_pixel cond, %(firstreg+1)
.if numbytes == 16
src_x888_8888_pixel cond, %(firstreg+2)
src_x888_8888_pixel cond, %(firstreg+3)
.endif
.endif
.endm
generate_composite_function \
pixman_composite_src_x888_8888_asm_armv6, 32, 0, 32, \
FLAG_DST_WRITEONLY | FLAG_COND_EXEC | FLAG_PROCESS_PRESERVES_SCRATCH, \
3, /* prefetch distance */ \
nop_macro, /* init */ \
nop_macro, /* newline */ \
nop_macro, /* cleanup */ \
pixman_composite_src_x888_8888_process_head, \
pixman_composite_src_x888_8888_process_tail
/******************************************************************************/
.macro src_0565_8888_init
/* Hold loop invariants in MASK and STRIDE_M */
ldr MASK, =0x07E007E0
mov STRIDE_M, #0xFF000000
/* Set GE[3:0] to 1010 so SEL instructions do what we want */
ldr SCRATCH, =0x80008000
uadd8 SCRATCH, SCRATCH, SCRATCH
.endm
.macro src_0565_8888_2pixels, reg1, reg2
and SCRATCH, WK&reg1, MASK @ 00000GGGGGG0000000000gggggg00000
bic WK&reg2, WK&reg1, MASK @ RRRRR000000BBBBBrrrrr000000bbbbb
orr SCRATCH, SCRATCH, SCRATCH, lsr #6 @ 00000GGGGGGGGGGGG0000ggggggggggg
mov WK&reg1, WK&reg2, lsl #16 @ rrrrr000000bbbbb0000000000000000
mov SCRATCH, SCRATCH, ror #19 @ GGGG0000ggggggggggg00000GGGGGGGG
bic WK&reg2, WK&reg2, WK&reg1, lsr #16 @ RRRRR000000BBBBB0000000000000000
orr WK&reg1, WK&reg1, WK&reg1, lsr #5 @ rrrrrrrrrr0bbbbbbbbbb00000000000
orr WK&reg2, WK&reg2, WK&reg2, lsr #5 @ RRRRRRRRRR0BBBBBBBBBB00000000000
pkhtb WK&reg1, WK&reg1, WK&reg1, asr #5 @ rrrrrrrr--------bbbbbbbb--------
sel WK&reg1, WK&reg1, SCRATCH @ rrrrrrrrggggggggbbbbbbbb--------
mov SCRATCH, SCRATCH, ror #16 @ ggg00000GGGGGGGGGGGG0000gggggggg
pkhtb WK&reg2, WK&reg2, WK&reg2, asr #5 @ RRRRRRRR--------BBBBBBBB--------
sel WK&reg2, WK&reg2, SCRATCH @ RRRRRRRRGGGGGGGGBBBBBBBB--------
orr WK&reg1, STRIDE_M, WK&reg1, lsr #8 @ 11111111rrrrrrrrggggggggbbbbbbbb
orr WK&reg2, STRIDE_M, WK&reg2, lsr #8 @ 11111111RRRRRRRRGGGGGGGGBBBBBBBB
.endm
/* This version doesn't need STRIDE_M, but is one instruction longer.
It would however be preferable for an XRGB target, since we could knock off the last 2 instructions, but is that a common case?
and SCRATCH, WK&reg1, MASK @ 00000GGGGGG0000000000gggggg00000
bic WK&reg1, WK&reg1, MASK @ RRRRR000000BBBBBrrrrr000000bbbbb
orr SCRATCH, SCRATCH, SCRATCH, lsr #6 @ 00000GGGGGGGGGGGG0000ggggggggggg
mov WK&reg2, WK&reg1, lsr #16 @ 0000000000000000RRRRR000000BBBBB
mov SCRATCH, SCRATCH, ror #27 @ GGGGGGGGGGGG0000ggggggggggg00000
bic WK&reg1, WK&reg1, WK&reg2, lsl #16 @ 0000000000000000rrrrr000000bbbbb
mov WK&reg2, WK&reg2, lsl #3 @ 0000000000000RRRRR000000BBBBB000
mov WK&reg1, WK&reg1, lsl #3 @ 0000000000000rrrrr000000bbbbb000
orr WK&reg2, WK&reg2, WK&reg2, lsr #5 @ 0000000000000RRRRRRRRRR0BBBBBBBB
orr WK&reg1, WK&reg1, WK&reg1, lsr #5 @ 0000000000000rrrrrrrrrr0bbbbbbbb
pkhbt WK&reg2, WK&reg2, WK&reg2, lsl #5 @ --------RRRRRRRR--------BBBBBBBB
pkhbt WK&reg1, WK&reg1, WK&reg1, lsl #5 @ --------rrrrrrrr--------bbbbbbbb
sel WK&reg2, SCRATCH, WK&reg2 @ --------RRRRRRRRGGGGGGGGBBBBBBBB
sel WK&reg1, SCRATCH, WK&reg1 @ --------rrrrrrrrggggggggbbbbbbbb
orr WK&reg2, WK&reg2, #0xFF000000 @ 11111111RRRRRRRRGGGGGGGGBBBBBBBB
orr WK&reg1, WK&reg1, #0xFF000000 @ 11111111rrrrrrrrggggggggbbbbbbbb
*/
.macro src_0565_8888_1pixel, reg
bic SCRATCH, WK&reg, MASK @ 0000000000000000rrrrr000000bbbbb
and WK&reg, WK&reg, MASK @ 000000000000000000000gggggg00000
mov SCRATCH, SCRATCH, lsl #3 @ 0000000000000rrrrr000000bbbbb000
mov WK&reg, WK&reg, lsl #5 @ 0000000000000000gggggg0000000000
orr SCRATCH, SCRATCH, SCRATCH, lsr #5 @ 0000000000000rrrrrrrrrr0bbbbbbbb
orr WK&reg, WK&reg, WK&reg, lsr #6 @ 000000000000000gggggggggggg00000
pkhbt SCRATCH, SCRATCH, SCRATCH, lsl #5 @ --------rrrrrrrr--------bbbbbbbb
sel WK&reg, WK&reg, SCRATCH @ --------rrrrrrrrggggggggbbbbbbbb
orr WK&reg, WK&reg, #0xFF000000 @ 11111111rrrrrrrrggggggggbbbbbbbb
.endm
.macro src_0565_8888_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload
.if numbytes == 16
pixldst ld,, 8, firstreg, %(firstreg+2),,, SRC, unaligned_src
.elseif numbytes == 8
pixld , 4, firstreg, SRC, unaligned_src
.elseif numbytes == 4
pixld , 2, firstreg, SRC, unaligned_src
.endif
.endm
.macro src_0565_8888_process_tail cond, numbytes, firstreg
.if numbytes == 16
src_0565_8888_2pixels firstreg, %(firstreg+1)
src_0565_8888_2pixels %(firstreg+2), %(firstreg+3)
.elseif numbytes == 8
src_0565_8888_2pixels firstreg, %(firstreg+1)
.else
src_0565_8888_1pixel firstreg
.endif
.endm
generate_composite_function \
pixman_composite_src_0565_8888_asm_armv6, 16, 0, 32, \
FLAG_DST_WRITEONLY | FLAG_BRANCH_OVER, \
3, /* prefetch distance */ \
src_0565_8888_init, \
nop_macro, /* newline */ \
nop_macro, /* cleanup */ \
src_0565_8888_process_head, \
src_0565_8888_process_tail
/******************************************************************************/
.macro add_8_8_8pixels cond, dst1, dst2
uqadd8&cond WK&dst1, WK&dst1, MASK
uqadd8&cond WK&dst2, WK&dst2, STRIDE_M
.endm
.macro add_8_8_4pixels cond, dst
uqadd8&cond WK&dst, WK&dst, MASK
.endm
.macro add_8_8_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload
WK4 .req MASK
WK5 .req STRIDE_M
.if numbytes == 16
pixld cond, 8, 4, SRC, unaligned_src
pixld cond, 16, firstreg, DST, 0
add_8_8_8pixels cond, firstreg, %(firstreg+1)
pixld cond, 8, 4, SRC, unaligned_src
.else
pixld cond, numbytes, 4, SRC, unaligned_src
pixld cond, numbytes, firstreg, DST, 0
.endif
.unreq WK4
.unreq WK5
.endm
.macro add_8_8_process_tail cond, numbytes, firstreg
.if numbytes == 16
add_8_8_8pixels cond, %(firstreg+2), %(firstreg+3)
.elseif numbytes == 8
add_8_8_8pixels cond, firstreg, %(firstreg+1)
.else
add_8_8_4pixels cond, firstreg
.endif
.endm
generate_composite_function \
pixman_composite_add_8_8_asm_armv6, 8, 0, 8, \
FLAG_DST_READWRITE | FLAG_BRANCH_OVER | FLAG_PROCESS_PRESERVES_SCRATCH, \
2, /* prefetch distance */ \
nop_macro, /* init */ \
nop_macro, /* newline */ \
nop_macro, /* cleanup */ \
add_8_8_process_head, \
add_8_8_process_tail
/******************************************************************************/
.macro over_8888_8888_init
/* Hold loop invariant in MASK */
ldr MASK, =0x00800080
/* Set GE[3:0] to 0101 so SEL instructions do what we want */
uadd8 SCRATCH, MASK, MASK
line_saved_regs STRIDE_D, STRIDE_S, ORIG_W
.endm
.macro over_8888_8888_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload
WK4 .req STRIDE_D
WK5 .req STRIDE_S
WK6 .req STRIDE_M
WK7 .req ORIG_W
pixld , numbytes, %(4+firstreg), SRC, unaligned_src
pixld , numbytes, firstreg, DST, 0
.unreq WK4
.unreq WK5
.unreq WK6
.unreq WK7
.endm
.macro over_8888_8888_check_transparent numbytes, reg0, reg1, reg2, reg3
/* Since these colours a premultiplied by alpha, only 0 indicates transparent (any other colour with 0 in the alpha byte is luminous) */
teq WK&reg0, #0
.if numbytes > 4
teqeq WK&reg1, #0
.if numbytes > 8
teqeq WK&reg2, #0
teqeq WK&reg3, #0
.endif
.endif
.endm
.macro over_8888_8888_prepare next
mov WK&next, WK&next, lsr #24
.endm
.macro over_8888_8888_1pixel src, dst, offset, next
/* src = destination component multiplier */
rsb WK&src, WK&src, #255
/* Split even/odd bytes of dst into SCRATCH/dst */
uxtb16 SCRATCH, WK&dst
uxtb16 WK&dst, WK&dst, ror #8
/* Multiply through, adding 0.5 to the upper byte of result for rounding */
mla SCRATCH, SCRATCH, WK&src, MASK
mla WK&dst, WK&dst, WK&src, MASK
/* Where we would have had a stall between the result of the first MLA and the shifter input,
* reload the complete source pixel */
ldr WK&src, [SRC, #offset]
/* Multiply by 257/256 to approximate 256/255 */
uxtab16 SCRATCH, SCRATCH, SCRATCH, ror #8
/* In this stall, start processing the next pixel */
.if offset < -4
mov WK&next, WK&next, lsr #24
.endif
uxtab16 WK&dst, WK&dst, WK&dst, ror #8
/* Recombine even/odd bytes of multiplied destination */
mov SCRATCH, SCRATCH, ror #8
sel WK&dst, SCRATCH, WK&dst
/* Saturated add of source to multiplied destination */
uqadd8 WK&dst, WK&dst, WK&src
.endm
.macro over_8888_8888_process_tail cond, numbytes, firstreg
WK4 .req STRIDE_D
WK5 .req STRIDE_S
WK6 .req STRIDE_M
WK7 .req ORIG_W
over_8888_8888_check_transparent numbytes, %(4+firstreg), %(5+firstreg), %(6+firstreg), %(7+firstreg)
beq 10f
over_8888_8888_prepare %(4+firstreg)
.set PROCESS_REG, firstreg
.set PROCESS_OFF, -numbytes
.rept numbytes / 4
over_8888_8888_1pixel %(4+PROCESS_REG), %(0+PROCESS_REG), PROCESS_OFF, %(5+PROCESS_REG)
.set PROCESS_REG, PROCESS_REG+1
.set PROCESS_OFF, PROCESS_OFF+4
.endr
pixst , numbytes, firstreg, DST
10:
.unreq WK4
.unreq WK5
.unreq WK6
.unreq WK7
.endm
generate_composite_function \
pixman_composite_over_8888_8888_asm_armv6, 32, 0, 32 \
FLAG_DST_READWRITE | FLAG_BRANCH_OVER | FLAG_PROCESS_CORRUPTS_PSR | FLAG_PROCESS_DOES_STORE | FLAG_SPILL_LINE_VARS \
2, /* prefetch distance */ \
over_8888_8888_init, \
nop_macro, /* newline */ \
nop_macro, /* cleanup */ \
over_8888_8888_process_head, \
over_8888_8888_process_tail
/******************************************************************************/
/* Multiply each byte of a word by a byte.
* Useful when there aren't any obvious ways to fill the stalls with other instructions.
* word Register containing 4 bytes
* byte Register containing byte multiplier (bits 8-31 must be 0)
* tmp Scratch register
* half Register containing the constant 0x00800080
* GE[3:0] bits must contain 0101
*/
.macro mul_8888_8 word, byte, tmp, half
/* Split even/odd bytes of word apart */
uxtb16 tmp, word
uxtb16 word, word, ror #8
/* Multiply bytes together with rounding, then by 257/256 */
mla tmp, tmp, byte, half
mla word, word, byte, half /* 1 stall follows */
uxtab16 tmp, tmp, tmp, ror #8 /* 1 stall follows */
uxtab16 word, word, word, ror #8
/* Recombine bytes */
mov tmp, tmp, ror #8
sel word, tmp, word
.endm
/******************************************************************************/
.macro over_8888_n_8888_init
/* Mask is constant */
ldr MASK, [sp, #ARGS_STACK_OFFSET+8]
/* Hold loop invariant in STRIDE_M */
ldr STRIDE_M, =0x00800080
/* We only want the alpha bits of the constant mask */
mov MASK, MASK, lsr #24
/* Set GE[3:0] to 0101 so SEL instructions do what we want */
uadd8 SCRATCH, STRIDE_M, STRIDE_M
line_saved_regs Y, STRIDE_D, STRIDE_S, ORIG_W
.endm
.macro over_8888_n_8888_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload
WK4 .req Y
WK5 .req STRIDE_D
WK6 .req STRIDE_S
WK7 .req ORIG_W
pixld , numbytes, %(4+(firstreg%2)), SRC, unaligned_src
pixld , numbytes, firstreg, DST, 0
.unreq WK4
.unreq WK5
.unreq WK6
.unreq WK7
.endm
.macro over_8888_n_8888_1pixel src, dst
mul_8888_8 WK&src, MASK, SCRATCH, STRIDE_M
sub WK7, WK6, WK&src, lsr #24
mul_8888_8 WK&dst, WK7, SCRATCH, STRIDE_M
uqadd8 WK&dst, WK&dst, WK&src
.endm
.macro over_8888_n_8888_process_tail cond, numbytes, firstreg
WK4 .req Y
WK5 .req STRIDE_D
WK6 .req STRIDE_S
WK7 .req ORIG_W
over_8888_8888_check_transparent numbytes, %(4+(firstreg%2)), %(5+(firstreg%2)), %(6+firstreg), %(7+firstreg)
beq 10f
mov WK6, #255
.set PROCESS_REG, firstreg
.rept numbytes / 4
.if numbytes == 16 && PROCESS_REG == 2
/* We're using WK6 and WK7 as temporaries, so half way through
* 4 pixels, reload the second two source pixels but this time
* into WK4 and WK5 */
ldmdb SRC, {WK4, WK5}
.endif
over_8888_n_8888_1pixel %(4+(PROCESS_REG%2)), %(PROCESS_REG)
.set PROCESS_REG, PROCESS_REG+1
.endr
pixst , numbytes, firstreg, DST
10:
.unreq WK4
.unreq WK5
.unreq WK6
.unreq WK7
.endm
generate_composite_function \
pixman_composite_over_8888_n_8888_asm_armv6, 32, 0, 32 \
FLAG_DST_READWRITE | FLAG_BRANCH_OVER | FLAG_PROCESS_CORRUPTS_PSR | FLAG_PROCESS_DOES_STORE | FLAG_SPILL_LINE_VARS \
2, /* prefetch distance */ \
over_8888_n_8888_init, \
nop_macro, /* newline */ \
nop_macro, /* cleanup */ \
over_8888_n_8888_process_head, \
over_8888_n_8888_process_tail
/******************************************************************************/
.macro over_n_8_8888_init
/* Source is constant, but splitting it into even/odd bytes is a loop invariant */
ldr SRC, [sp, #ARGS_STACK_OFFSET]
/* Not enough registers to hold this constant, but we still use it here to set GE[3:0] */
ldr SCRATCH, =0x00800080
uxtb16 STRIDE_S, SRC
uxtb16 SRC, SRC, ror #8
/* Set GE[3:0] to 0101 so SEL instructions do what we want */
uadd8 SCRATCH, SCRATCH, SCRATCH
line_saved_regs Y, STRIDE_D, STRIDE_M, ORIG_W
.endm
.macro over_n_8_8888_newline
ldr STRIDE_D, =0x00800080
b 1f
.ltorg
1:
.endm
.macro over_n_8_8888_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload
WK4 .req STRIDE_M
pixld , numbytes/4, 4, MASK, unaligned_mask
pixld , numbytes, firstreg, DST, 0
.unreq WK4
.endm
.macro over_n_8_8888_1pixel src, dst
uxtb Y, WK4, ror #src*8
/* Trailing part of multiplication of source */
mla SCRATCH, STRIDE_S, Y, STRIDE_D
mla Y, SRC, Y, STRIDE_D
mov ORIG_W, #255
uxtab16 SCRATCH, SCRATCH, SCRATCH, ror #8
uxtab16 Y, Y, Y, ror #8
mov SCRATCH, SCRATCH, ror #8
sub ORIG_W, ORIG_W, Y, lsr #24
sel Y, SCRATCH, Y
/* Then multiply the destination */
mul_8888_8 WK&dst, ORIG_W, SCRATCH, STRIDE_D
uqadd8 WK&dst, WK&dst, Y
.endm
.macro over_n_8_8888_process_tail cond, numbytes, firstreg
WK4 .req STRIDE_M
teq WK4, #0
beq 10f
.set PROCESS_REG, firstreg
.rept numbytes / 4
over_n_8_8888_1pixel %(PROCESS_REG-firstreg), %(PROCESS_REG)
.set PROCESS_REG, PROCESS_REG+1
.endr
pixst , numbytes, firstreg, DST
10:
.unreq WK4
.endm
generate_composite_function \
pixman_composite_over_n_8_8888_asm_armv6, 0, 8, 32 \
FLAG_DST_READWRITE | FLAG_BRANCH_OVER | FLAG_PROCESS_CORRUPTS_PSR | FLAG_PROCESS_DOES_STORE | FLAG_SPILL_LINE_VARS \
2, /* prefetch distance */ \
over_n_8_8888_init, \
over_n_8_8888_newline, \
nop_macro, /* cleanup */ \
over_n_8_8888_process_head, \
over_n_8_8888_process_tail
/******************************************************************************/

View file

@ -0,0 +1,912 @@
/*
* Copyright © 2012 Raspberry Pi Foundation
* Copyright © 2012 RISC OS Open Ltd
*
* 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 the copyright holders not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. The copyright holders make 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.
*
* Author: Ben Avison (bavison@riscosopen.org)
*
*/
/*
* Because the alignment of pixel data to cachelines, and even the number of
* cachelines per row can vary from row to row, and because of the need to
* preload each scanline once and only once, this prefetch strategy treats
* each row of pixels independently. When a pixel row is long enough, there
* are three distinct phases of prefetch:
* * an inner loop section, where each time a cacheline of data is
* processed, another cacheline is preloaded (the exact distance ahead is
* determined empirically using profiling results from lowlevel-blt-bench)
* * a leading section, where enough cachelines are preloaded to ensure no
* cachelines escape being preloaded when the inner loop starts
* * a trailing section, where a limited number (0 or more) of cachelines
* are preloaded to deal with data (if any) that hangs off the end of the
* last iteration of the inner loop, plus any trailing bytes that were not
* enough to make up one whole iteration of the inner loop
*
* There are (in general) three distinct code paths, selected between
* depending upon how long the pixel row is. If it is long enough that there
* is at least one iteration of the inner loop (as described above) then
* this is described as the "wide" case. If it is shorter than that, but
* there are still enough bytes output that there is at least one 16-byte-
* long, 16-byte-aligned write to the destination (the optimum type of
* write), then this is the "medium" case. If it is not even this long, then
* this is the "narrow" case, and there is no attempt to align writes to
* 16-byte boundaries. In the "medium" and "narrow" cases, all the
* cachelines containing data from the pixel row are prefetched up-front.
*/
/*
* Determine whether we put the arguments on the stack for debugging.
*/
#undef DEBUG_PARAMS
/*
* Bit flags for 'generate_composite_function' macro which are used
* to tune generated functions behavior.
*/
.set FLAG_DST_WRITEONLY, 0
.set FLAG_DST_READWRITE, 1
.set FLAG_COND_EXEC, 0
.set FLAG_BRANCH_OVER, 2
.set FLAG_PROCESS_PRESERVES_PSR, 0
.set FLAG_PROCESS_CORRUPTS_PSR, 4
.set FLAG_PROCESS_DOESNT_STORE, 0
.set FLAG_PROCESS_DOES_STORE, 8 /* usually because it needs to conditionally skip it */
.set FLAG_NO_SPILL_LINE_VARS, 0
.set FLAG_SPILL_LINE_VARS_WIDE, 16
.set FLAG_SPILL_LINE_VARS_NON_WIDE, 32
.set FLAG_SPILL_LINE_VARS, 48
.set FLAG_PROCESS_CORRUPTS_SCRATCH, 0
.set FLAG_PROCESS_PRESERVES_SCRATCH, 64
/*
* Offset into stack where mask and source pointer/stride can be accessed.
*/
#ifdef DEBUG_PARAMS
.set ARGS_STACK_OFFSET, (9*4+9*4)
#else
.set ARGS_STACK_OFFSET, (9*4)
#endif
/*
* Constants for selecting preferable prefetch type.
*/
.set PREFETCH_TYPE_NONE, 0
.set PREFETCH_TYPE_STANDARD, 1
/*
* Definitions of macros for load/store of pixel data.
*/
.macro pixldst op, cond=al, numbytes, reg0, reg1, reg2, reg3, base, unaligned=0
.if numbytes == 16
.if unaligned == 1
op&r&cond WK&reg0, [base], #4
op&r&cond WK&reg1, [base], #4
op&r&cond WK&reg2, [base], #4
op&r&cond WK&reg3, [base], #4
.else
op&m&cond&ia base!, {WK&reg0,WK&reg1,WK&reg2,WK&reg3}
.endif
.elseif numbytes == 8
.if unaligned == 1
op&r&cond WK&reg0, [base], #4
op&r&cond WK&reg1, [base], #4
.else
op&m&cond&ia base!, {WK&reg0,WK&reg1}
.endif
.elseif numbytes == 4
op&r&cond WK&reg0, [base], #4
.elseif numbytes == 2
op&r&cond&h WK&reg0, [base], #2
.elseif numbytes == 1
op&r&cond&b WK&reg0, [base], #1
.else
.error "unsupported size: numbytes"
.endif
.endm
.macro pixst_baseupdated cond, numbytes, reg0, reg1, reg2, reg3, base
.if numbytes == 16
stm&cond&db base, {WK&reg0,WK&reg1,WK&reg2,WK&reg3}
.elseif numbytes == 8
stm&cond&db base, {WK&reg0,WK&reg1}
.elseif numbytes == 4
str&cond WK&reg0, [base, #-4]
.elseif numbytes == 2
str&cond&h WK&reg0, [base, #-2]
.elseif numbytes == 1
str&cond&b WK&reg0, [base, #-1]
.else
.error "unsupported size: numbytes"
.endif
.endm
.macro pixld cond, numbytes, firstreg, base, unaligned
pixldst ld, cond, numbytes, %(firstreg+0), %(firstreg+1), %(firstreg+2), %(firstreg+3), base, unaligned
.endm
.macro pixst cond, numbytes, firstreg, base
.if (flags) & FLAG_DST_READWRITE
pixst_baseupdated cond, numbytes, %(firstreg+0), %(firstreg+1), %(firstreg+2), %(firstreg+3), base
.else
pixldst st, cond, numbytes, %(firstreg+0), %(firstreg+1), %(firstreg+2), %(firstreg+3), base
.endif
.endm
.macro PF a, x:vararg
.if (PREFETCH_TYPE_CURRENT == PREFETCH_TYPE_STANDARD)
a x
.endif
.endm
.macro preload_leading_step1 bpp, ptr, base
/* If the destination is already 16-byte aligned, then we need to preload
* between 0 and prefetch_distance (inclusive) cache lines ahead so there
* are no gaps when the inner loop starts.
*/
.if bpp > 0
PF bic, ptr, base, #31
.set OFFSET, 0
.rept prefetch_distance+1
PF pld, [ptr, #OFFSET]
.set OFFSET, OFFSET+32
.endr
.endif
.endm
.macro preload_leading_step2 bpp, bpp_shift, ptr, base
/* However, if the destination is not 16-byte aligned, we may need to
* preload more cache lines than that. The question we need to ask is:
* are the bytes corresponding to the leading pixels more than the amount
* by which the source pointer will be rounded down for preloading, and if
* so, by how many cache lines? Effectively, we want to calculate
* leading_bytes = ((-dst)&15)*src_bpp/dst_bpp
* inner_loop_offset = (src+leading_bytes)&31
* extra_needed = leading_bytes - inner_loop_offset
* and test if extra_needed is <= 0, <= 32, or > 32 (where > 32 is only
* possible when there are 4 src bytes for every 1 dst byte).
*/
.if bpp > 0
.ifc base,DST
/* The test can be simplified further when preloading the destination */
PF tst, base, #16
PF beq, 61f
.else
.if bpp/dst_w_bpp == 4
PF add, SCRATCH, base, WK0, lsl #bpp_shift-dst_bpp_shift
PF and, SCRATCH, SCRATCH, #31
PF rsb, SCRATCH, SCRATCH, WK0, lsl #bpp_shift-dst_bpp_shift
PF sub, SCRATCH, SCRATCH, #1 /* so now ranges are -16..-1 / 0..31 / 32..63 */
PF movs, SCRATCH, SCRATCH, #32-6 /* so this sets NC / nc / Nc */
PF bcs, 61f
PF bpl, 60f
PF pld, [ptr, #32*(prefetch_distance+2)]
.else
PF mov, SCRATCH, base, lsl #32-5
PF add, SCRATCH, SCRATCH, WK0, lsl #32-5+bpp_shift-dst_bpp_shift
PF rsbs, SCRATCH, SCRATCH, WK0, lsl #32-5+bpp_shift-dst_bpp_shift
PF bls, 61f
.endif
.endif
60: PF pld, [ptr, #32*(prefetch_distance+1)]
61:
.endif
.endm
#define IS_END_OF_GROUP(INDEX,SIZE) ((SIZE) < 2 || ((INDEX) & ~((INDEX)+1)) & ((SIZE)/2))
.macro preload_middle bpp, base, scratch_holds_offset
.if bpp > 0
/* prefetch distance = 256/bpp, stm distance = 128/dst_w_bpp */
.if IS_END_OF_GROUP(SUBBLOCK,256/128*dst_w_bpp/bpp)
.if scratch_holds_offset
PF pld, [base, SCRATCH]
.else
PF bic, SCRATCH, base, #31
PF pld, [SCRATCH, #32*prefetch_distance]
.endif
.endif
.endif
.endm
.macro preload_trailing bpp, bpp_shift, base
.if bpp > 0
.if bpp*pix_per_block > 256
/* Calculations are more complex if more than one fetch per block */
PF and, WK1, base, #31
PF add, WK1, WK1, WK0, lsl #bpp_shift
PF add, WK1, WK1, #32*(bpp*pix_per_block/256-1)*(prefetch_distance+1)
PF bic, SCRATCH, base, #31
80: PF pld, [SCRATCH, #32*(prefetch_distance+1)]
PF add, SCRATCH, SCRATCH, #32
PF subs, WK1, WK1, #32
PF bhi, 80b
.else
/* If exactly one fetch per block, then we need either 0, 1 or 2 extra preloads */
PF mov, SCRATCH, base, lsl #32-5
PF adds, SCRATCH, SCRATCH, X, lsl #32-5+bpp_shift
PF adceqs, SCRATCH, SCRATCH, #0
/* The instruction above has two effects: ensures Z is only
* set if C was clear (so Z indicates that both shifted quantities
* were 0), and clears C if Z was set (so C indicates that the sum
* of the shifted quantities was greater and not equal to 32) */
PF beq, 82f
PF bic, SCRATCH, base, #31
PF bcc, 81f
PF pld, [SCRATCH, #32*(prefetch_distance+2)]
81: PF pld, [SCRATCH, #32*(prefetch_distance+1)]
82:
.endif
.endif
.endm
.macro preload_line narrow_case, bpp, bpp_shift, base
/* "narrow_case" - just means that the macro was invoked from the "narrow"
* code path rather than the "medium" one - because in the narrow case,
* the row of pixels is known to output no more than 30 bytes, then
* (assuming the source pixels are no wider than the the destination
* pixels) they cannot possibly straddle more than 2 32-byte cachelines,
* meaning there's no need for a loop.
* "bpp" - number of bits per pixel in the channel (source, mask or
* destination) that's being preloaded, or 0 if this channel is not used
* for reading
* "bpp_shift" - log2 of ("bpp"/8) (except if "bpp"=0 of course)
* "base" - base address register of channel to preload (SRC, MASK or DST)
*/
.if bpp > 0
.if narrow_case && (bpp <= dst_w_bpp)
/* In these cases, each line for each channel is in either 1 or 2 cache lines */
PF bic, WK0, base, #31
PF pld, [WK0]
PF add, WK1, base, X, LSL #bpp_shift
PF sub, WK1, WK1, #1
PF bic, WK1, WK1, #31
PF cmp, WK1, WK0
PF beq, 90f
PF pld, [WK1]
90:
.else
PF bic, WK0, base, #31
PF pld, [WK0]
PF add, WK1, base, X, lsl #bpp_shift
PF sub, WK1, WK1, #1
PF bic, WK1, WK1, #31
PF cmp, WK1, WK0
PF beq, 92f
91: PF add, WK0, WK0, #32
PF cmp, WK0, WK1
PF pld, [WK0]
PF bne, 91b
92:
.endif
.endif
.endm
.macro conditional_process1_helper cond, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx
process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, 0
.if decrementx
sub&cond X, X, #8*numbytes/dst_w_bpp
.endif
process_tail cond, numbytes, firstreg
.if !((flags) & FLAG_PROCESS_DOES_STORE)
pixst cond, numbytes, firstreg, DST
.endif
.endm
.macro conditional_process1 cond, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx
.if (flags) & FLAG_BRANCH_OVER
.ifc cond,mi
bpl 100f
.endif
.ifc cond,cs
bcc 100f
.endif
.ifc cond,ne
beq 100f
.endif
conditional_process1_helper , process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx
100:
.else
conditional_process1_helper cond, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx
.endif
.endm
.macro conditional_process2 test, cond1, cond2, process_head, process_tail, numbytes1, numbytes2, firstreg1, firstreg2, unaligned_src, unaligned_mask, decrementx
.if (flags) & (FLAG_DST_READWRITE | FLAG_BRANCH_OVER | FLAG_PROCESS_CORRUPTS_PSR | FLAG_PROCESS_DOES_STORE)
/* Can't interleave reads and writes */
test
conditional_process1 cond1, process_head, process_tail, numbytes1, firstreg1, unaligned_src, unaligned_mask, decrementx
.if (flags) & FLAG_PROCESS_CORRUPTS_PSR
test
.endif
conditional_process1 cond2, process_head, process_tail, numbytes2, firstreg2, unaligned_src, unaligned_mask, decrementx
.else
/* Can interleave reads and writes for better scheduling */
test
process_head cond1, numbytes1, firstreg1, unaligned_src, unaligned_mask, 0
process_head cond2, numbytes2, firstreg2, unaligned_src, unaligned_mask, 0
.if decrementx
sub&cond1 X, X, #8*numbytes1/dst_w_bpp
sub&cond2 X, X, #8*numbytes2/dst_w_bpp
.endif
process_tail cond1, numbytes1, firstreg1
process_tail cond2, numbytes2, firstreg2
pixst cond1, numbytes1, firstreg1, DST
pixst cond2, numbytes2, firstreg2, DST
.endif
.endm
.macro test_bits_1_0_ptr
movs SCRATCH, WK0, lsl #32-1 /* C,N = bits 1,0 of DST */
.endm
.macro test_bits_3_2_ptr
movs SCRATCH, WK0, lsl #32-3 /* C,N = bits 3, 2 of DST */
.endm
.macro leading_15bytes process_head, process_tail
/* On entry, WK0 bits 0-3 = number of bytes until destination is 16-byte aligned */
/* Use unaligned loads in all cases for simplicity */
.if dst_w_bpp == 8
conditional_process2 test_bits_1_0_ptr, mi, cs, process_head, process_tail, 1, 2, 1, 2, 1, 1, 1
.elseif dst_w_bpp == 16
test_bits_1_0_ptr
conditional_process1 cs, process_head, process_tail, 2, 2, 1, 1, 1
.endif
conditional_process2 test_bits_3_2_ptr, mi, cs, process_head, process_tail, 4, 8, 1, 2, 1, 1, 1
.endm
.macro test_bits_3_2_pix
movs SCRATCH, X, lsl #dst_bpp_shift+32-3
.endm
.macro test_bits_1_0_pix
.if dst_w_bpp == 8
movs SCRATCH, X, lsl #dst_bpp_shift+32-1
.else
movs SCRATCH, X, lsr #1
.endif
.endm
.macro trailing_15bytes process_head, process_tail, unaligned_src, unaligned_mask
conditional_process2 test_bits_3_2_pix, cs, mi, process_head, process_tail, 8, 4, 0, 2, unaligned_src, unaligned_mask, 0
.if dst_w_bpp == 16
test_bits_1_0_pix
conditional_process1 cs, process_head, process_tail, 2, 0, unaligned_src, unaligned_mask, 0
.elseif dst_w_bpp == 8
conditional_process2 test_bits_1_0_pix, cs, mi, process_head, process_tail, 2, 1, 0, 1, unaligned_src, unaligned_mask, 0
.endif
.endm
.macro wide_case_inner_loop process_head, process_tail, unaligned_src, unaligned_mask, dst_alignment
110:
.set SUBBLOCK, 0 /* this is a count of STMs; there can be up to 8 STMs per block */
.rept pix_per_block*dst_w_bpp/128
process_head , 16, 0, unaligned_src, unaligned_mask, 1
.if (src_bpp > 0) && (mask_bpp == 0) && ((flags) & FLAG_PROCESS_PRESERVES_SCRATCH)
preload_middle src_bpp, SRC, 1
.elseif (src_bpp == 0) && (mask_bpp > 0) && ((flags) & FLAG_PROCESS_PRESERVES_SCRATCH)
preload_middle mask_bpp, MASK, 1
.else
preload_middle src_bpp, SRC, 0
preload_middle mask_bpp, MASK, 0
.endif
.if (dst_r_bpp > 0) && ((SUBBLOCK % 2) == 0)
/* Because we know that writes are 16-byte aligned, it's relatively easy to ensure that
* destination prefetches are 32-byte aligned. It's also the easiest channel to offset
* preloads for, to achieve staggered prefetches for multiple channels, because there are
* always two STMs per prefetch, so there is always an opposite STM on which to put the
* preload. Note, no need to BIC the base register here */
PF pld, [DST, #32*prefetch_distance - dst_alignment]
.endif
process_tail , 16, 0
.if !((flags) & FLAG_PROCESS_DOES_STORE)
pixst , 16, 0, DST
.endif
.set SUBBLOCK, SUBBLOCK+1
.endr
subs X, X, #pix_per_block
bhs 110b
.endm
.macro wide_case_inner_loop_and_trailing_pixels process_head, process_tail, process_inner_loop, exit_label, unaligned_src, unaligned_mask
/* Destination now 16-byte aligned; we have at least one block before we have to stop preloading */
.if dst_r_bpp > 0
tst DST, #16
bne 111f
process_inner_loop process_head, process_tail, unaligned_src, unaligned_mask, 16
b 112f
111:
.endif
process_inner_loop process_head, process_tail, unaligned_src, unaligned_mask, 0
112:
/* Just before the final (prefetch_distance+1) 32-byte blocks, deal with final preloads */
.if (src_bpp*pix_per_block > 256) || (mask_bpp*pix_per_block > 256) || (dst_r_bpp*pix_per_block > 256)
PF and, WK0, X, #pix_per_block-1
.endif
preload_trailing src_bpp, src_bpp_shift, SRC
preload_trailing mask_bpp, mask_bpp_shift, MASK
preload_trailing dst_r_bpp, dst_bpp_shift, DST
add X, X, #(prefetch_distance+2)*pix_per_block - 128/dst_w_bpp
/* The remainder of the line is handled identically to the medium case */
medium_case_inner_loop_and_trailing_pixels process_head, process_tail,, exit_label, unaligned_src, unaligned_mask
.endm
.macro medium_case_inner_loop_and_trailing_pixels process_head, process_tail, unused, exit_label, unaligned_src, unaligned_mask
120:
process_head , 16, 0, unaligned_src, unaligned_mask, 0
process_tail , 16, 0
.if !((flags) & FLAG_PROCESS_DOES_STORE)
pixst , 16, 0, DST
.endif
subs X, X, #128/dst_w_bpp
bhs 120b
/* Trailing pixels */
tst X, #128/dst_w_bpp - 1
beq exit_label
trailing_15bytes process_head, process_tail, unaligned_src, unaligned_mask
.endm
.macro narrow_case_inner_loop_and_trailing_pixels process_head, process_tail, unused, exit_label, unaligned_src, unaligned_mask
tst X, #16*8/dst_w_bpp
conditional_process1 ne, process_head, process_tail, 16, 0, unaligned_src, unaligned_mask, 0
/* Trailing pixels */
/* In narrow case, it's relatively unlikely to be aligned, so let's do without a branch here */
trailing_15bytes process_head, process_tail, unaligned_src, unaligned_mask
.endm
.macro switch_on_alignment action, process_head, process_tail, process_inner_loop, exit_label
/* Note that if we're reading the destination, it's already guaranteed to be aligned at this point */
.if mask_bpp == 8 || mask_bpp == 16
tst MASK, #3
bne 141f
.endif
.if src_bpp == 8 || src_bpp == 16
tst SRC, #3
bne 140f
.endif
action process_head, process_tail, process_inner_loop, exit_label, 0, 0
.if src_bpp == 8 || src_bpp == 16
b exit_label
140:
action process_head, process_tail, process_inner_loop, exit_label, 1, 0
.endif
.if mask_bpp == 8 || mask_bpp == 16
b exit_label
141:
.if src_bpp == 8 || src_bpp == 16
tst SRC, #3
bne 142f
.endif
action process_head, process_tail, process_inner_loop, exit_label, 0, 1
.if src_bpp == 8 || src_bpp == 16
b exit_label
142:
action process_head, process_tail, process_inner_loop, exit_label, 1, 1
.endif
.endif
.endm
.macro end_of_line restore_x, vars_spilled, loop_label, last_one
.if vars_spilled
/* Sadly, GAS doesn't seem have an equivalent of the DCI directive? */
/* This is ldmia sp,{} */
.word 0xE89D0000 | LINE_SAVED_REGS
.endif
subs Y, Y, #1
.if vars_spilled
.if (LINE_SAVED_REGS) & (1<<1)
str Y, [sp]
.endif
.endif
add DST, DST, STRIDE_D
.if src_bpp > 0
add SRC, SRC, STRIDE_S
.endif
.if mask_bpp > 0
add MASK, MASK, STRIDE_M
.endif
.if restore_x
mov X, ORIG_W
.endif
bhs loop_label
.ifc "last_one",""
.if vars_spilled
b 197f
.else
b 198f
.endif
.else
.if (!vars_spilled) && ((flags) & FLAG_SPILL_LINE_VARS)
b 198f
.endif
.endif
.endm
.macro generate_composite_function fname, \
src_bpp_, \
mask_bpp_, \
dst_w_bpp_, \
flags_, \
prefetch_distance_, \
init, \
newline, \
cleanup, \
process_head, \
process_tail, \
process_inner_loop
.func fname
.global fname
/* For ELF format also set function visibility to hidden */
#ifdef __ELF__
.hidden fname
.type fname, %function
#endif
/*
* Make some macro arguments globally visible and accessible
* from other macros
*/
.set src_bpp, src_bpp_
.set mask_bpp, mask_bpp_
.set dst_w_bpp, dst_w_bpp_
.set flags, flags_
.set prefetch_distance, prefetch_distance_
/*
* Select prefetch type for this function.
*/
.if prefetch_distance == 0
.set PREFETCH_TYPE_CURRENT, PREFETCH_TYPE_NONE
.else
.set PREFETCH_TYPE_CURRENT, PREFETCH_TYPE_STANDARD
.endif
.if src_bpp == 32
.set src_bpp_shift, 2
.elseif src_bpp == 24
.set src_bpp_shift, 0
.elseif src_bpp == 16
.set src_bpp_shift, 1
.elseif src_bpp == 8
.set src_bpp_shift, 0
.elseif src_bpp == 0
.set src_bpp_shift, -1
.else
.error "requested src bpp (src_bpp) is not supported"
.endif
.if mask_bpp == 32
.set mask_bpp_shift, 2
.elseif mask_bpp == 24
.set mask_bpp_shift, 0
.elseif mask_bpp == 8
.set mask_bpp_shift, 0
.elseif mask_bpp == 0
.set mask_bpp_shift, -1
.else
.error "requested mask bpp (mask_bpp) is not supported"
.endif
.if dst_w_bpp == 32
.set dst_bpp_shift, 2
.elseif dst_w_bpp == 24
.set dst_bpp_shift, 0
.elseif dst_w_bpp == 16
.set dst_bpp_shift, 1
.elseif dst_w_bpp == 8
.set dst_bpp_shift, 0
.else
.error "requested dst bpp (dst_w_bpp) is not supported"
.endif
.if (((flags) & FLAG_DST_READWRITE) != 0)
.set dst_r_bpp, dst_w_bpp
.else
.set dst_r_bpp, 0
.endif
.set pix_per_block, 16*8/dst_w_bpp
.if src_bpp != 0
.if 32*8/src_bpp > pix_per_block
.set pix_per_block, 32*8/src_bpp
.endif
.endif
.if mask_bpp != 0
.if 32*8/mask_bpp > pix_per_block
.set pix_per_block, 32*8/mask_bpp
.endif
.endif
.if dst_r_bpp != 0
.if 32*8/dst_r_bpp > pix_per_block
.set pix_per_block, 32*8/dst_r_bpp
.endif
.endif
/* The standard entry conditions set up by pixman-arm-common.h are:
* r0 = width (pixels)
* r1 = height (rows)
* r2 = pointer to top-left pixel of destination
* r3 = destination stride (pixels)
* [sp] = source pixel value, or pointer to top-left pixel of source
* [sp,#4] = 0 or source stride (pixels)
* The following arguments are unused for non-mask operations
* [sp,#8] = mask pixel value, or pointer to top-left pixel of mask
* [sp,#12] = 0 or mask stride (pixels)
*/
/*
* Assign symbolic names to registers
*/
X .req r0 /* pixels to go on this line */
Y .req r1 /* lines to go */
DST .req r2 /* destination pixel pointer */
STRIDE_D .req r3 /* destination stride (bytes, minus width) */
SRC .req r4 /* source pixel pointer */
STRIDE_S .req r5 /* source stride (bytes, minus width) */
MASK .req r6 /* mask pixel pointer (if applicable) */
STRIDE_M .req r7 /* mask stride (bytes, minus width) */
WK0 .req r8 /* pixel data registers */
WK1 .req r9
WK2 .req r10
WK3 .req r11
SCRATCH .req r12
ORIG_W .req r14 /* width (pixels) */
fname:
.fnstart
.save {r4-r11, lr}
push {r4-r11, lr} /* save all registers */
subs Y, Y, #1
blo 199f
#ifdef DEBUG_PARAMS
.pad #9*4
sub sp, sp, #9*4
#endif
.if src_bpp > 0
ldr SRC, [sp, #ARGS_STACK_OFFSET]
ldr STRIDE_S, [sp, #ARGS_STACK_OFFSET+4]
.endif
.if mask_bpp > 0
ldr MASK, [sp, #ARGS_STACK_OFFSET+8]
ldr STRIDE_M, [sp, #ARGS_STACK_OFFSET+12]
.endif
#ifdef DEBUG_PARAMS
add Y, Y, #1
stmia sp, {r0-r7,pc}
sub Y, Y, #1
#endif
init
lsl STRIDE_D, #dst_bpp_shift /* stride in bytes */
sub STRIDE_D, STRIDE_D, X, lsl #dst_bpp_shift
.if src_bpp > 0
lsl STRIDE_S, #src_bpp_shift
sub STRIDE_S, STRIDE_S, X, lsl #src_bpp_shift
.endif
.if mask_bpp > 0
lsl STRIDE_M, #mask_bpp_shift
sub STRIDE_M, STRIDE_M, X, lsl #mask_bpp_shift
.endif
/* Are we not even wide enough to have one 16-byte aligned 16-byte block write? */
cmp X, #2*16*8/dst_w_bpp - 1
blo 170f
.if src_bpp || mask_bpp || dst_r_bpp /* Wide and medium cases are the same for fill */
/* To preload ahead on the current line, we need at least (prefetch_distance+2) 32-byte blocks on all prefetch channels */
cmp X, #(prefetch_distance+3)*pix_per_block - 1
blo 160f
/* Wide case */
/* Adjust X so that the decrement instruction can also test for
* inner loop termination. We want it to stop when there are
* (prefetch_distance+1) complete blocks to go. */
sub X, X, #(prefetch_distance+2)*pix_per_block
mov ORIG_W, X
.if (flags) & FLAG_SPILL_LINE_VARS_WIDE
/* This is stmdb sp!,{} */
.word 0xE92D0000 | LINE_SAVED_REGS
.endif
151: /* New line */
newline
preload_leading_step1 src_bpp, WK1, SRC
preload_leading_step1 mask_bpp, WK2, MASK
preload_leading_step1 dst_r_bpp, WK3, DST
tst DST, #15
beq 154f
rsb WK0, DST, #0 /* bits 0-3 = number of leading bytes until destination aligned */
.if (src_bpp != 0 && src_bpp != 2*dst_w_bpp) || (mask_bpp != 0 && mask_bpp != 2*dst_w_bpp)
PF and, WK0, WK0, #15
.endif
preload_leading_step2 src_bpp, src_bpp_shift, WK1, SRC
preload_leading_step2 mask_bpp, mask_bpp_shift, WK2, MASK
preload_leading_step2 dst_r_bpp, dst_bpp_shift, WK3, DST
leading_15bytes process_head, process_tail
154: /* Destination now 16-byte aligned; we have at least one prefetch on each channel as well as at least one 16-byte output block */
.if (src_bpp > 0) && (mask_bpp == 0) && ((flags) & FLAG_PROCESS_PRESERVES_SCRATCH)
and SCRATCH, SRC, #31
rsb SCRATCH, SCRATCH, #32*prefetch_distance
.elseif (src_bpp == 0) && (mask_bpp > 0) && ((flags) & FLAG_PROCESS_PRESERVES_SCRATCH)
and SCRATCH, MASK, #31
rsb SCRATCH, SCRATCH, #32*prefetch_distance
.endif
.ifc "process_inner_loop",""
switch_on_alignment wide_case_inner_loop_and_trailing_pixels, process_head, process_tail, wide_case_inner_loop, 157f
.else
switch_on_alignment wide_case_inner_loop_and_trailing_pixels, process_head, process_tail, process_inner_loop, 157f
.endif
157: /* Check for another line */
end_of_line 1, %((flags) & FLAG_SPILL_LINE_VARS_WIDE), 151b
.endif
.ltorg
160: /* Medium case */
mov ORIG_W, X
.if (flags) & FLAG_SPILL_LINE_VARS_NON_WIDE
/* This is stmdb sp!,{} */
.word 0xE92D0000 | LINE_SAVED_REGS
.endif
161: /* New line */
newline
preload_line 0, src_bpp, src_bpp_shift, SRC /* in: X, corrupts: WK0-WK1 */
preload_line 0, mask_bpp, mask_bpp_shift, MASK
preload_line 0, dst_r_bpp, dst_bpp_shift, DST
sub X, X, #128/dst_w_bpp /* simplifies inner loop termination */
tst DST, #15
beq 164f
rsb WK0, DST, #0 /* bits 0-3 = number of leading bytes until destination aligned */
leading_15bytes process_head, process_tail
164: /* Destination now 16-byte aligned; we have at least one 16-byte output block */
switch_on_alignment medium_case_inner_loop_and_trailing_pixels, process_head, process_tail,, 167f
167: /* Check for another line */
end_of_line 1, %((flags) & FLAG_SPILL_LINE_VARS_NON_WIDE), 161b
.ltorg
170: /* Narrow case, less than 31 bytes, so no guarantee of at least one 16-byte block */
.if dst_w_bpp < 32
mov ORIG_W, X
.endif
.if (flags) & FLAG_SPILL_LINE_VARS_NON_WIDE
/* This is stmdb sp!,{} */
.word 0xE92D0000 | LINE_SAVED_REGS
.endif
171: /* New line */
newline
preload_line 1, src_bpp, src_bpp_shift, SRC /* in: X, corrupts: WK0-WK1 */
preload_line 1, mask_bpp, mask_bpp_shift, MASK
preload_line 1, dst_r_bpp, dst_bpp_shift, DST
.if dst_w_bpp == 8
tst DST, #3
beq 174f
172: subs X, X, #1
blo 177f
process_head , 1, 0, 1, 1, 0
process_tail , 1, 0
.if !((flags) & FLAG_PROCESS_DOES_STORE)
pixst , 1, 0, DST
.endif
tst DST, #3
bne 172b
.elseif dst_w_bpp == 16
tst DST, #2
beq 174f
subs X, X, #1
blo 177f
process_head , 2, 0, 1, 1, 0
process_tail , 2, 0
.if !((flags) & FLAG_PROCESS_DOES_STORE)
pixst , 2, 0, DST
.endif
.endif
174: /* Destination now 4-byte aligned; we have 0 or more output bytes to go */
switch_on_alignment narrow_case_inner_loop_and_trailing_pixels, process_head, process_tail,, 177f
177: /* Check for another line */
end_of_line %(dst_w_bpp < 32), %((flags) & FLAG_SPILL_LINE_VARS_NON_WIDE), 171b, last_one
197:
.if (flags) & FLAG_SPILL_LINE_VARS
add sp, sp, #LINE_SAVED_REG_COUNT*4
.endif
198:
cleanup
#ifdef DEBUG_PARAMS
add sp, sp, #9*4 /* junk the debug copy of arguments */
#endif
199:
pop {r4-r11, pc} /* exit */
.fnend
.ltorg
.unreq X
.unreq Y
.unreq DST
.unreq STRIDE_D
.unreq SRC
.unreq STRIDE_S
.unreq MASK
.unreq STRIDE_M
.unreq WK0
.unreq WK1
.unreq WK2
.unreq WK3
.unreq SCRATCH
.unreq ORIG_W
.endfunc
.endm
.macro line_saved_regs x:vararg
.set LINE_SAVED_REGS, 0
.set LINE_SAVED_REG_COUNT, 0
.irp SAVED_REG,x
.ifc "SAVED_REG","Y"
.set LINE_SAVED_REGS, LINE_SAVED_REGS | (1<<1)
.set LINE_SAVED_REG_COUNT, LINE_SAVED_REG_COUNT + 1
.endif
.ifc "SAVED_REG","STRIDE_D"
.set LINE_SAVED_REGS, LINE_SAVED_REGS | (1<<3)
.set LINE_SAVED_REG_COUNT, LINE_SAVED_REG_COUNT + 1
.endif
.ifc "SAVED_REG","STRIDE_S"
.set LINE_SAVED_REGS, LINE_SAVED_REGS | (1<<5)
.set LINE_SAVED_REG_COUNT, LINE_SAVED_REG_COUNT + 1
.endif
.ifc "SAVED_REG","STRIDE_M"
.set LINE_SAVED_REGS, LINE_SAVED_REGS | (1<<7)
.set LINE_SAVED_REG_COUNT, LINE_SAVED_REG_COUNT + 1
.endif
.ifc "SAVED_REG","ORIG_W"
.set LINE_SAVED_REGS, LINE_SAVED_REGS | (1<<14)
.set LINE_SAVED_REG_COUNT, LINE_SAVED_REG_COUNT + 1
.endif
.endr
.endm
.macro nop_macro x:vararg
.endm

View file

@ -0,0 +1,257 @@
/*
* Copyright © 2008 Mozilla 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 Mozilla Corporation not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Mozilla Corporation 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.
*
* Author: Jeff Muizelaar (jeff@infidigm.net)
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "pixman-private.h"
#include "pixman-arm-common.h"
#include "pixman-inlines.h"
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, src_8888_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, src_x888_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, src_0565_0565,
uint16_t, 1, uint16_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, src_8_8,
uint8_t, 1, uint8_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, src_0565_8888,
uint16_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, add_8_8,
uint8_t, 1, uint8_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_DST (armv6, over_8888_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, armv6, over_8888_n_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, armv6, over_n_8_8888,
uint8_t, 1, uint32_t, 1)
PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_DST (armv6, 0565_0565, SRC,
uint16_t, uint16_t)
PIXMAN_ARM_BIND_SCALED_NEAREST_SRC_DST (armv6, 8888_8888, SRC,
uint32_t, uint32_t)
void
pixman_composite_src_n_8888_asm_armv6 (int32_t w,
int32_t h,
uint32_t *dst,
int32_t dst_stride,
uint32_t src);
void
pixman_composite_src_n_0565_asm_armv6 (int32_t w,
int32_t h,
uint16_t *dst,
int32_t dst_stride,
uint16_t src);
void
pixman_composite_src_n_8_asm_armv6 (int32_t w,
int32_t h,
uint8_t *dst,
int32_t dst_stride,
uint8_t src);
static pixman_bool_t
arm_simd_fill (pixman_implementation_t *imp,
uint32_t * bits,
int stride, /* in 32-bit words */
int bpp,
int x,
int y,
int width,
int height,
uint32_t _xor)
{
/* stride is always multiple of 32bit units in pixman */
uint32_t byte_stride = stride * sizeof(uint32_t);
switch (bpp)
{
case 8:
pixman_composite_src_n_8_asm_armv6 (
width,
height,
(uint8_t *)(((char *) bits) + y * byte_stride + x),
byte_stride,
_xor & 0xff);
return TRUE;
case 16:
pixman_composite_src_n_0565_asm_armv6 (
width,
height,
(uint16_t *)(((char *) bits) + y * byte_stride + x * 2),
byte_stride / 2,
_xor & 0xffff);
return TRUE;
case 32:
pixman_composite_src_n_8888_asm_armv6 (
width,
height,
(uint32_t *)(((char *) bits) + y * byte_stride + x * 4),
byte_stride / 4,
_xor);
return TRUE;
default:
return FALSE;
}
}
static pixman_bool_t
arm_simd_blt (pixman_implementation_t *imp,
uint32_t * src_bits,
uint32_t * dst_bits,
int src_stride, /* in 32-bit words */
int dst_stride, /* in 32-bit words */
int src_bpp,
int dst_bpp,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height)
{
if (src_bpp != dst_bpp)
return FALSE;
switch (src_bpp)
{
case 8:
pixman_composite_src_8_8_asm_armv6 (
width, height,
(uint8_t *)(((char *) dst_bits) +
dest_y * dst_stride * 4 + dest_x * 1), dst_stride * 4,
(uint8_t *)(((char *) src_bits) +
src_y * src_stride * 4 + src_x * 1), src_stride * 4);
return TRUE;
case 16:
pixman_composite_src_0565_0565_asm_armv6 (
width, height,
(uint16_t *)(((char *) dst_bits) +
dest_y * dst_stride * 4 + dest_x * 2), dst_stride * 2,
(uint16_t *)(((char *) src_bits) +
src_y * src_stride * 4 + src_x * 2), src_stride * 2);
return TRUE;
case 32:
pixman_composite_src_8888_8888_asm_armv6 (
width, height,
(uint32_t *)(((char *) dst_bits) +
dest_y * dst_stride * 4 + dest_x * 4), dst_stride,
(uint32_t *)(((char *) src_bits) +
src_y * src_stride * 4 + src_x * 4), src_stride);
return TRUE;
default:
return FALSE;
}
}
static const pixman_fast_path_t arm_simd_fast_paths[] =
{
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, a8r8g8b8, armv6_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, a8b8g8r8, armv6_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, x8r8g8b8, armv6_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, x8b8g8r8, armv6_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, x8r8g8b8, armv6_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, x8b8g8r8, armv6_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, a8b8g8r8, armv6_composite_src_x888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, a8r8g8b8, armv6_composite_src_x888_8888),
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, r5g6b5, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, b5g6r5, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, a1r5g5b5, null, a1r5g5b5, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, a1b5g5r5, null, a1b5g5r5, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, a1r5g5b5, null, x1r5g5b5, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, a1b5g5r5, null, x1b5g5r5, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, x1r5g5b5, null, x1r5g5b5, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, x1b5g5r5, null, x1b5g5r5, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, a4r4g4b4, null, a4r4g4b4, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, a4b4g4r4, null, a4b4g4r4, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, a4r4g4b4, null, x4r4g4b4, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, a4b4g4r4, null, x4b4g4r4, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, x4r4g4b4, null, x4r4g4b4, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, x4b4g4r4, null, x4b4g4r4, armv6_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, a8, null, a8, armv6_composite_src_8_8),
PIXMAN_STD_FAST_PATH (SRC, r3g3b2, null, r3g3b2, armv6_composite_src_8_8),
PIXMAN_STD_FAST_PATH (SRC, b2g3r3, null, b2g3r3, armv6_composite_src_8_8),
PIXMAN_STD_FAST_PATH (SRC, a2r2g2b2, null, a2r2g2b2, armv6_composite_src_8_8),
PIXMAN_STD_FAST_PATH (SRC, a2b2g2r2, null, a2b2g2r2, armv6_composite_src_8_8),
PIXMAN_STD_FAST_PATH (SRC, c8, null, c8, armv6_composite_src_8_8),
PIXMAN_STD_FAST_PATH (SRC, g8, null, g8, armv6_composite_src_8_8),
PIXMAN_STD_FAST_PATH (SRC, x4a4, null, x4a4, armv6_composite_src_8_8),
PIXMAN_STD_FAST_PATH (SRC, x4c4, null, x4c4, armv6_composite_src_8_8),
PIXMAN_STD_FAST_PATH (SRC, x4g4, null, x4g4, armv6_composite_src_8_8),
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, a8r8g8b8, armv6_composite_src_0565_8888),
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, x8r8g8b8, armv6_composite_src_0565_8888),
PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, a8b8g8r8, armv6_composite_src_0565_8888),
PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, x8b8g8r8, armv6_composite_src_0565_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, a8r8g8b8, armv6_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, x8r8g8b8, armv6_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, a8b8g8r8, armv6_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, x8b8g8r8, armv6_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, a8r8g8b8, armv6_composite_over_8888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, x8r8g8b8, armv6_composite_over_8888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, a8b8g8r8, armv6_composite_over_8888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, x8b8g8r8, armv6_composite_over_8888_n_8888),
PIXMAN_STD_FAST_PATH (ADD, a8, null, a8, armv6_composite_add_8_8),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8r8g8b8, armv6_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8r8g8b8, armv6_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8b8g8r8, armv6_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8b8g8r8, armv6_composite_over_n_8_8888),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, r5g6b5, r5g6b5, armv6_0565_0565),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, b5g6r5, b5g6r5, armv6_0565_0565),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, armv6_8888_8888),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, armv6_8888_8888),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, armv6_8888_8888),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, a8b8g8r8, armv6_8888_8888),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, a8b8g8r8, x8b8g8r8, armv6_8888_8888),
PIXMAN_ARM_SIMPLE_NEAREST_FAST_PATH (SRC, x8b8g8r8, x8b8g8r8, armv6_8888_8888),
{ PIXMAN_OP_NONE },
};
pixman_implementation_t *
_pixman_implementation_create_arm_simd (pixman_implementation_t *fallback)
{
pixman_implementation_t *imp = _pixman_implementation_create (fallback, arm_simd_fast_paths);
imp->blt = arm_simd_blt;
imp->fill = arm_simd_fill;
return imp;
}

View file

@ -0,0 +1,229 @@
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
*
* 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 SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* 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 "pixman-private.h"
typedef enum
{
ARM_V7 = (1 << 0),
ARM_V6 = (1 << 1),
ARM_VFP = (1 << 2),
ARM_NEON = (1 << 3),
ARM_IWMMXT = (1 << 4)
} arm_cpu_features_t;
#if defined(USE_ARM_SIMD) || defined(USE_ARM_NEON) || defined(USE_ARM_IWMMXT)
#if defined(_MSC_VER)
/* Needed for EXCEPTION_ILLEGAL_INSTRUCTION */
#include <windows.h>
extern int pixman_msvc_try_arm_neon_op ();
extern int pixman_msvc_try_arm_simd_op ();
static arm_cpu_features_t
detect_cpu_features (void)
{
arm_cpu_features_t features = 0;
__try
{
pixman_msvc_try_arm_simd_op ();
features |= ARM_V6;
}
__except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION)
{
}
__try
{
pixman_msvc_try_arm_neon_op ();
features |= ARM_NEON;
}
__except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION)
{
}
return features;
}
#elif defined(__APPLE__) && defined(TARGET_OS_IPHONE) /* iOS */
#include "TargetConditionals.h"
static arm_cpu_features_t
detect_cpu_features (void)
{
arm_cpu_features_t features = 0;
features |= ARM_V6;
/* Detection of ARM NEON on iOS is fairly simple because iOS binaries
* contain separate executable images for each processor architecture.
* So all we have to do is detect the armv7 architecture build. The
* operating system automatically runs the armv7 binary for armv7 devices
* and the armv6 binary for armv6 devices.
*/
#if defined(__ARM_NEON__)
features |= ARM_NEON;
#endif
return features;
}
#elif defined(__ANDROID__) || defined(ANDROID) /* Android */
static arm_cpu_features_t
detect_cpu_features (void)
{
arm_cpu_features_t features = 0;
char buf[1024];
char* pos;
const char* ver_token = "CPU architecture: ";
FILE* f = fopen("/proc/cpuinfo", "r");
if (!f) {
return features;
}
fread(buf, sizeof(char), sizeof(buf), f);
fclose(f);
pos = strstr(buf, ver_token);
if (pos) {
char vchar = *(pos + strlen(ver_token));
if (vchar >= '0' && vchar <= '9') {
int ver = vchar - '0';
if (ver >= 7)
features |= ARM_V7;
}
}
if (strstr(buf, "neon") != NULL)
features |= ARM_NEON;
if (strstr(buf, "vfp") != NULL)
features |= ARM_VFP;
return features;
}
#elif defined (__linux__) /* linux ELF */
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <elf.h>
static arm_cpu_features_t
detect_cpu_features (void)
{
arm_cpu_features_t features = 0;
Elf32_auxv_t aux;
int fd;
fd = open ("/proc/self/auxv", O_RDONLY);
if (fd >= 0)
{
while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t))
{
if (aux.a_type == AT_HWCAP)
{
uint32_t hwcap = aux.a_un.a_val;
/* hardcode these values to avoid depending on specific
* versions of the hwcap header, e.g. HWCAP_NEON
*/
if ((hwcap & 64) != 0)
features |= ARM_VFP;
if ((hwcap & 512) != 0)
features |= ARM_IWMMXT;
/* this flag is only present on kernel 2.6.29 */
if ((hwcap & 4096) != 0)
features |= ARM_NEON;
}
else if (aux.a_type == AT_PLATFORM)
{
const char *plat = (const char*) aux.a_un.a_val;
if (strncmp (plat, "v7l", 3) == 0)
features |= (ARM_V7 | ARM_V6);
else if (strncmp (plat, "v6l", 3) == 0)
features |= ARM_V6;
}
}
close (fd);
}
return features;
}
#else /* Unknown */
static arm_cpu_features_t
detect_cpu_features (void)
{
return 0;
}
#endif /* Linux elf */
static pixman_bool_t
have_feature (arm_cpu_features_t feature)
{
static pixman_bool_t initialized;
static arm_cpu_features_t features;
if (!initialized)
{
features = detect_cpu_features();
initialized = TRUE;
}
return (features & feature) == feature;
}
#endif /* USE_ARM_SIMD || USE_ARM_NEON || USE_ARM_IWMMXT */
pixman_implementation_t *
_pixman_arm_get_implementations (pixman_implementation_t *imp)
{
#ifdef USE_ARM_SIMD
if (!_pixman_disabled ("arm-simd") && have_feature (ARM_V6))
imp = _pixman_implementation_create_arm_simd (imp);
#endif
#ifdef USE_ARM_IWMMXT
if (!_pixman_disabled ("arm-iwmmxt") && have_feature (ARM_IWMMXT))
imp = _pixman_implementation_create_mmx (imp);
#endif
#ifdef USE_ARM_NEON
if (!_pixman_disabled ("arm-neon") && have_feature (ARM_NEON))
imp = _pixman_implementation_create_arm_neon (imp);
#endif
return imp;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,226 @@
#define COMPONENT_SIZE
#define MASK
#define ONE_HALF
#define A_SHIFT
#define R_SHIFT
#define G_SHIFT
#define A_MASK
#define R_MASK
#define G_MASK
#define RB_MASK
#define AG_MASK
#define RB_ONE_HALF
#define RB_MASK_PLUS_ONE
#define ALPHA_c(x) ((x) >> A_SHIFT)
#define RED_c(x) (((x) >> R_SHIFT) & MASK)
#define GREEN_c(x) (((x) >> G_SHIFT) & MASK)
#define BLUE_c(x) ((x) & MASK)
/*
* Helper macros.
*/
#define MUL_UNc(a, b, t) \
((t) = (a) * (comp2_t)(b) + ONE_HALF, ((((t) >> G_SHIFT ) + (t) ) >> G_SHIFT ))
#define DIV_UNc(a, b) \
(((comp2_t) (a) * MASK + ((b) / 2)) / (b))
#define ADD_UNc(x, y, t) \
((t) = (x) + (y), \
(comp4_t) (comp1_t) ((t) | (0 - ((t) >> G_SHIFT))))
#define DIV_ONE_UNc(x) \
(((x) + ONE_HALF + (((x) + ONE_HALF) >> G_SHIFT)) >> G_SHIFT)
/*
* The methods below use some tricks to be able to do two color
* components at the same time.
*/
/*
* x_rb = (x_rb * a) / 255
*/
#define UNc_rb_MUL_UNc(x, a, t) \
do \
{ \
t = ((x) & RB_MASK) * (a); \
t += RB_ONE_HALF; \
x = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \
x &= RB_MASK; \
} while (0)
/*
* x_rb = min (x_rb + y_rb, 255)
*/
#define UNc_rb_ADD_UNc_rb(x, y, t) \
do \
{ \
t = ((x) + (y)); \
t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK); \
x = (t & RB_MASK); \
} while (0)
/*
* x_rb = (x_rb * a_rb) / 255
*/
#define UNc_rb_MUL_UNc_rb(x, a, t) \
do \
{ \
t = (x & MASK) * (a & MASK); \
t |= (x & R_MASK) * ((a >> R_SHIFT) & MASK); \
t += RB_ONE_HALF; \
t = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \
x = t & RB_MASK; \
} while (0)
/*
* x_c = (x_c * a) / 255
*/
#define UNcx4_MUL_UNc(x, a) \
do \
{ \
comp4_t r1__, r2__, t__; \
\
r1__ = (x); \
UNc_rb_MUL_UNc (r1__, (a), t__); \
\
r2__ = (x) >> G_SHIFT; \
UNc_rb_MUL_UNc (r2__, (a), t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a) / 255 + y_c
*/
#define UNcx4_MUL_UNc_ADD_UNcx4(x, a, y) \
do \
{ \
comp4_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (y) & RB_MASK; \
UNc_rb_MUL_UNc (r1__, (a), t__); \
UNc_rb_ADD_UNc_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UNc_rb_MUL_UNc (r2__, (a), t__); \
UNc_rb_ADD_UNc_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a + y_c * b) / 255
*/
#define UNcx4_MUL_UNc_ADD_UNcx4_MUL_UNc(x, a, y, b) \
do \
{ \
comp4_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (y); \
UNc_rb_MUL_UNc (r1__, (a), t__); \
UNc_rb_MUL_UNc (r2__, (b), t__); \
UNc_rb_ADD_UNc_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT); \
r3__ = ((y) >> G_SHIFT); \
UNc_rb_MUL_UNc (r2__, (a), t__); \
UNc_rb_MUL_UNc (r3__, (b), t__); \
UNc_rb_ADD_UNc_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a_c) / 255
*/
#define UNcx4_MUL_UNcx4(x, a) \
do \
{ \
comp4_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UNc_rb_MUL_UNc_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = (a) >> G_SHIFT; \
UNc_rb_MUL_UNc_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a_c) / 255 + y_c
*/
#define UNcx4_MUL_UNcx4_ADD_UNcx4(x, a, y) \
do \
{ \
comp4_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UNc_rb_MUL_UNc_rb (r1__, r2__, t__); \
r2__ = (y) & RB_MASK; \
UNc_rb_ADD_UNc_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT); \
r3__ = ((a) >> G_SHIFT); \
UNc_rb_MUL_UNc_rb (r2__, r3__, t__); \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UNc_rb_ADD_UNc_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a_c + y_c * b) / 255
*/
#define UNcx4_MUL_UNcx4_ADD_UNcx4_MUL_UNc(x, a, y, b) \
do \
{ \
comp4_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UNc_rb_MUL_UNc_rb (r1__, r2__, t__); \
r2__ = (y); \
UNc_rb_MUL_UNc (r2__, (b), t__); \
UNc_rb_ADD_UNc_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = (a) >> G_SHIFT; \
UNc_rb_MUL_UNc_rb (r2__, r3__, t__); \
r3__ = (y) >> G_SHIFT; \
UNc_rb_MUL_UNc (r3__, (b), t__); \
UNc_rb_ADD_UNc_rb (r2__, r3__, t__); \
\
x = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
x_c = min(x_c + y_c, 255)
*/
#define UNcx4_ADD_UNcx4(x, y) \
do \
{ \
comp4_t r1__, r2__, r3__, t__; \
\
r1__ = (x) & RB_MASK; \
r2__ = (y) & RB_MASK; \
UNc_rb_ADD_UNc_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT) & RB_MASK; \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UNc_rb_ADD_UNc_rb (r2__, r3__, t__); \
\
x = r1__ | (r2__ << G_SHIFT); \
} while (0)

View file

@ -0,0 +1,114 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <math.h>
#include <string.h>
#include "pixman-private.h"
#include "pixman-combine32.h"
static force_inline uint32_t
combine_mask (const uint32_t src, const uint32_t mask)
{
uint32_t s, m;
m = mask >> A_SHIFT;
if (!m)
return 0;
s = src;
UN8x4_MUL_UN8 (s, m);
return s;
}
static void
combine_src_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
if (!mask)
memcpy (dest, src, width * sizeof (uint16_t));
else
{
uint16_t *d = (uint16_t*)dest;
uint16_t *src16 = (uint16_t*)src;
for (i = 0; i < width; ++i)
{
if ((*mask & 0xff000000) == 0xff000000) {
// it's likely worth special casing
// fully opaque because it avoids
// the cost of conversion as well the multiplication
*(d + i) = *src16;
} else {
// the mask is still 32bits
uint32_t s = combine_mask (convert_0565_to_8888(*src16), *mask);
*(d + i) = convert_8888_to_0565(s);
}
mask++;
src16++;
}
}
}
static void
combine_over_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
int i;
if (!mask)
memcpy (dest, src, width * sizeof (uint16_t));
else
{
uint16_t *d = (uint16_t*)dest;
uint16_t *src16 = (uint16_t*)src;
for (i = 0; i < width; ++i)
{
if ((*mask & 0xff000000) == 0xff000000) {
// it's likely worth special casing
// fully opaque because it avoids
// the cost of conversion as well the multiplication
*(d + i) = *src16;
} else if ((*mask & 0xff000000) == 0x00000000) {
// keep the dest the same
} else {
// the mask is still 32bits
uint32_t s = combine_mask (convert_0565_to_8888(*src16), *mask);
uint32_t ia = ALPHA_8 (~s);
uint32_t d32 = convert_0565_to_8888(*(d + i));
UN8x4_MUL_UN8_ADD_UN8x4 (d32, ia, s);
*(d + i) = convert_8888_to_0565(d32);
}
mask++;
src16++;
}
}
}
void
_pixman_setup_combiner_functions_16 (pixman_implementation_t *imp)
{
int i;
for (i = 0; i < PIXMAN_N_OPERATORS; i++) {
imp->combine_16[i] = NULL;
}
imp->combine_16[PIXMAN_OP_SRC] = combine_src_u;
imp->combine_16[PIXMAN_OP_OVER] = combine_over_u;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,272 @@
#define COMPONENT_SIZE 8
#define MASK 0xff
#define ONE_HALF 0x80
#define A_SHIFT 8 * 3
#define R_SHIFT 8 * 2
#define G_SHIFT 8
#define A_MASK 0xff000000
#define R_MASK 0xff0000
#define G_MASK 0xff00
#define RB_MASK 0xff00ff
#define AG_MASK 0xff00ff00
#define RB_ONE_HALF 0x800080
#define RB_MASK_PLUS_ONE 0x10000100
#define ALPHA_8(x) ((x) >> A_SHIFT)
#define RED_8(x) (((x) >> R_SHIFT) & MASK)
#define GREEN_8(x) (((x) >> G_SHIFT) & MASK)
#define BLUE_8(x) ((x) & MASK)
/*
* ARMv6 has UQADD8 instruction, which implements unsigned saturated
* addition for 8-bit values packed in 32-bit registers. It is very useful
* for UN8x4_ADD_UN8x4, UN8_rb_ADD_UN8_rb and ADD_UN8 macros (which would
* otherwise need a lot of arithmetic operations to simulate this operation).
* Since most of the major ARM linux distros are built for ARMv7, we are
* much less dependent on runtime CPU detection and can get practical
* benefits from conditional compilation here for a lot of users.
*/
#if defined(USE_GCC_INLINE_ASM) && defined(__arm__) && \
!defined(__aarch64__) && (!defined(__thumb__) || defined(__thumb2__))
#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) || \
defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7__) || \
defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \
defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
static force_inline uint32_t
un8x4_add_un8x4 (uint32_t x, uint32_t y)
{
uint32_t t;
asm ("uqadd8 %0, %1, %2" : "=r" (t) : "%r" (x), "r" (y));
return t;
}
#define UN8x4_ADD_UN8x4(x, y) \
((x) = un8x4_add_un8x4 ((x), (y)))
#define UN8_rb_ADD_UN8_rb(x, y, t) \
((t) = un8x4_add_un8x4 ((x), (y)), (x) = (t))
#define ADD_UN8(x, y, t) \
((t) = (x), un8x4_add_un8x4 ((t), (y)))
#endif
#endif
/*****************************************************************************/
/*
* Helper macros.
*/
#define MUL_UN8(a, b, t) \
((t) = (a) * (uint16_t)(b) + ONE_HALF, ((((t) >> G_SHIFT ) + (t) ) >> G_SHIFT ))
#define DIV_UN8(a, b) \
(((uint16_t) (a) * MASK + ((b) / 2)) / (b))
#ifndef ADD_UN8
#define ADD_UN8(x, y, t) \
((t) = (x) + (y), \
(uint32_t) (uint8_t) ((t) | (0 - ((t) >> G_SHIFT))))
#endif
#define DIV_ONE_UN8(x) \
(((x) + ONE_HALF + (((x) + ONE_HALF) >> G_SHIFT)) >> G_SHIFT)
/*
* The methods below use some tricks to be able to do two color
* components at the same time.
*/
/*
* x_rb = (x_rb * a) / 255
*/
#define UN8_rb_MUL_UN8(x, a, t) \
do \
{ \
t = ((x) & RB_MASK) * (a); \
t += RB_ONE_HALF; \
x = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \
x &= RB_MASK; \
} while (0)
/*
* x_rb = min (x_rb + y_rb, 255)
*/
#ifndef UN8_rb_ADD_UN8_rb
#define UN8_rb_ADD_UN8_rb(x, y, t) \
do \
{ \
t = ((x) + (y)); \
t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK); \
x = (t & RB_MASK); \
} while (0)
#endif
/*
* x_rb = (x_rb * a_rb) / 255
*/
#define UN8_rb_MUL_UN8_rb(x, a, t) \
do \
{ \
t = (x & MASK) * (a & MASK); \
t |= (x & R_MASK) * ((a >> R_SHIFT) & MASK); \
t += RB_ONE_HALF; \
t = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \
x = t & RB_MASK; \
} while (0)
/*
* x_c = (x_c * a) / 255
*/
#define UN8x4_MUL_UN8(x, a) \
do \
{ \
uint32_t r1__, r2__, t__; \
\
r1__ = (x); \
UN8_rb_MUL_UN8 (r1__, (a), t__); \
\
r2__ = (x) >> G_SHIFT; \
UN8_rb_MUL_UN8 (r2__, (a), t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a) / 255 + y_c
*/
#define UN8x4_MUL_UN8_ADD_UN8x4(x, a, y) \
do \
{ \
uint32_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (y) & RB_MASK; \
UN8_rb_MUL_UN8 (r1__, (a), t__); \
UN8_rb_ADD_UN8_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UN8_rb_MUL_UN8 (r2__, (a), t__); \
UN8_rb_ADD_UN8_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a + y_c * b) / 255
*/
#define UN8x4_MUL_UN8_ADD_UN8x4_MUL_UN8(x, a, y, b) \
do \
{ \
uint32_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (y); \
UN8_rb_MUL_UN8 (r1__, (a), t__); \
UN8_rb_MUL_UN8 (r2__, (b), t__); \
UN8_rb_ADD_UN8_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT); \
r3__ = ((y) >> G_SHIFT); \
UN8_rb_MUL_UN8 (r2__, (a), t__); \
UN8_rb_MUL_UN8 (r3__, (b), t__); \
UN8_rb_ADD_UN8_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a_c) / 255
*/
#define UN8x4_MUL_UN8x4(x, a) \
do \
{ \
uint32_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UN8_rb_MUL_UN8_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = (a) >> G_SHIFT; \
UN8_rb_MUL_UN8_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a_c) / 255 + y_c
*/
#define UN8x4_MUL_UN8x4_ADD_UN8x4(x, a, y) \
do \
{ \
uint32_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UN8_rb_MUL_UN8_rb (r1__, r2__, t__); \
r2__ = (y) & RB_MASK; \
UN8_rb_ADD_UN8_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT); \
r3__ = ((a) >> G_SHIFT); \
UN8_rb_MUL_UN8_rb (r2__, r3__, t__); \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UN8_rb_ADD_UN8_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a_c + y_c * b) / 255
*/
#define UN8x4_MUL_UN8x4_ADD_UN8x4_MUL_UN8(x, a, y, b) \
do \
{ \
uint32_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UN8_rb_MUL_UN8_rb (r1__, r2__, t__); \
r2__ = (y); \
UN8_rb_MUL_UN8 (r2__, (b), t__); \
UN8_rb_ADD_UN8_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = (a) >> G_SHIFT; \
UN8_rb_MUL_UN8_rb (r2__, r3__, t__); \
r3__ = (y) >> G_SHIFT; \
UN8_rb_MUL_UN8 (r3__, (b), t__); \
UN8_rb_ADD_UN8_rb (r2__, r3__, t__); \
\
x = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
x_c = min(x_c + y_c, 255)
*/
#ifndef UN8x4_ADD_UN8x4
#define UN8x4_ADD_UN8x4(x, y) \
do \
{ \
uint32_t r1__, r2__, r3__, t__; \
\
r1__ = (x) & RB_MASK; \
r2__ = (y) & RB_MASK; \
UN8_rb_ADD_UN8_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT) & RB_MASK; \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UN8_rb_ADD_UN8_rb (r2__, r3__, t__); \
\
x = r1__ | (r2__ << G_SHIFT); \
} while (0)
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,230 @@
/* WARNING: This file is generated by combine.pl from combine.inc.
Please edit one of those files rather than this one. */
#line 1 "pixman-combine.c.template"
#define COMPONENT_SIZE 16
#define MASK 0xffffULL
#define ONE_HALF 0x8000ULL
#define A_SHIFT 16 * 3
#define R_SHIFT 16 * 2
#define G_SHIFT 16
#define A_MASK 0xffff000000000000ULL
#define R_MASK 0xffff00000000ULL
#define G_MASK 0xffff0000ULL
#define RB_MASK 0xffff0000ffffULL
#define AG_MASK 0xffff0000ffff0000ULL
#define RB_ONE_HALF 0x800000008000ULL
#define RB_MASK_PLUS_ONE 0x10000000010000ULL
#define ALPHA_16(x) ((x) >> A_SHIFT)
#define RED_16(x) (((x) >> R_SHIFT) & MASK)
#define GREEN_16(x) (((x) >> G_SHIFT) & MASK)
#define BLUE_16(x) ((x) & MASK)
/*
* Helper macros.
*/
#define MUL_UN16(a, b, t) \
((t) = (a) * (uint32_t)(b) + ONE_HALF, ((((t) >> G_SHIFT ) + (t) ) >> G_SHIFT ))
#define DIV_UN16(a, b) \
(((uint32_t) (a) * MASK + ((b) / 2)) / (b))
#define ADD_UN16(x, y, t) \
((t) = (x) + (y), \
(uint64_t) (uint16_t) ((t) | (0 - ((t) >> G_SHIFT))))
#define DIV_ONE_UN16(x) \
(((x) + ONE_HALF + (((x) + ONE_HALF) >> G_SHIFT)) >> G_SHIFT)
/*
* The methods below use some tricks to be able to do two color
* components at the same time.
*/
/*
* x_rb = (x_rb * a) / 255
*/
#define UN16_rb_MUL_UN16(x, a, t) \
do \
{ \
t = ((x) & RB_MASK) * (a); \
t += RB_ONE_HALF; \
x = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \
x &= RB_MASK; \
} while (0)
/*
* x_rb = min (x_rb + y_rb, 255)
*/
#define UN16_rb_ADD_UN16_rb(x, y, t) \
do \
{ \
t = ((x) + (y)); \
t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK); \
x = (t & RB_MASK); \
} while (0)
/*
* x_rb = (x_rb * a_rb) / 255
*/
#define UN16_rb_MUL_UN16_rb(x, a, t) \
do \
{ \
t = (x & MASK) * (a & MASK); \
t |= (x & R_MASK) * ((a >> R_SHIFT) & MASK); \
t += RB_ONE_HALF; \
t = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \
x = t & RB_MASK; \
} while (0)
/*
* x_c = (x_c * a) / 255
*/
#define UN16x4_MUL_UN16(x, a) \
do \
{ \
uint64_t r1__, r2__, t__; \
\
r1__ = (x); \
UN16_rb_MUL_UN16 (r1__, (a), t__); \
\
r2__ = (x) >> G_SHIFT; \
UN16_rb_MUL_UN16 (r2__, (a), t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a) / 255 + y_c
*/
#define UN16x4_MUL_UN16_ADD_UN16x4(x, a, y) \
do \
{ \
uint64_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (y) & RB_MASK; \
UN16_rb_MUL_UN16 (r1__, (a), t__); \
UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UN16_rb_MUL_UN16 (r2__, (a), t__); \
UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a + y_c * b) / 255
*/
#define UN16x4_MUL_UN16_ADD_UN16x4_MUL_UN16(x, a, y, b) \
do \
{ \
uint64_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (y); \
UN16_rb_MUL_UN16 (r1__, (a), t__); \
UN16_rb_MUL_UN16 (r2__, (b), t__); \
UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT); \
r3__ = ((y) >> G_SHIFT); \
UN16_rb_MUL_UN16 (r2__, (a), t__); \
UN16_rb_MUL_UN16 (r3__, (b), t__); \
UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a_c) / 255
*/
#define UN16x4_MUL_UN16x4(x, a) \
do \
{ \
uint64_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UN16_rb_MUL_UN16_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = (a) >> G_SHIFT; \
UN16_rb_MUL_UN16_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a_c) / 255 + y_c
*/
#define UN16x4_MUL_UN16x4_ADD_UN16x4(x, a, y) \
do \
{ \
uint64_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UN16_rb_MUL_UN16_rb (r1__, r2__, t__); \
r2__ = (y) & RB_MASK; \
UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT); \
r3__ = ((a) >> G_SHIFT); \
UN16_rb_MUL_UN16_rb (r2__, r3__, t__); \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \
\
(x) = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
* x_c = (x_c * a_c + y_c * b) / 255
*/
#define UN16x4_MUL_UN16x4_ADD_UN16x4_MUL_UN16(x, a, y, b) \
do \
{ \
uint64_t r1__, r2__, r3__, t__; \
\
r1__ = (x); \
r2__ = (a); \
UN16_rb_MUL_UN16_rb (r1__, r2__, t__); \
r2__ = (y); \
UN16_rb_MUL_UN16 (r2__, (b), t__); \
UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \
\
r2__ = (x) >> G_SHIFT; \
r3__ = (a) >> G_SHIFT; \
UN16_rb_MUL_UN16_rb (r2__, r3__, t__); \
r3__ = (y) >> G_SHIFT; \
UN16_rb_MUL_UN16 (r3__, (b), t__); \
UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \
\
x = r1__ | (r2__ << G_SHIFT); \
} while (0)
/*
x_c = min(x_c + y_c, 255)
*/
#define UN16x4_ADD_UN16x4(x, y) \
do \
{ \
uint64_t r1__, r2__, r3__, t__; \
\
r1__ = (x) & RB_MASK; \
r2__ = (y) & RB_MASK; \
UN16_rb_ADD_UN16_rb (r1__, r2__, t__); \
\
r2__ = ((x) >> G_SHIFT) & RB_MASK; \
r3__ = ((y) >> G_SHIFT) & RB_MASK; \
UN16_rb_ADD_UN16_rb (r2__, r3__, t__); \
\
x = r1__ | (r2__ << G_SHIFT); \
} while (0)

View file

@ -0,0 +1,247 @@
/* Pixman uses some non-standard compiler features. This file ensures
* they exist
*
* The features are:
*
* FUNC must be defined to expand to the current function
* PIXMAN_EXPORT should be defined to whatever is required to
* export functions from a shared library
* limits limits for various types must be defined
* inline must be defined
* force_inline must be defined
*/
#if defined (__GNUC__)
# define FUNC ((const char*) (__PRETTY_FUNCTION__))
#elif defined (__sun) || (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
# define FUNC ((const char*) (__func__))
#else
# define FUNC ((const char*) ("???"))
#endif
#if defined (__GNUC__)
# define MAYBE_UNUSED __attribute__((unused))
#else
# define MAYBE_UNUSED
#endif
#ifndef INT16_MIN
# define INT16_MIN (-32767-1)
#endif
#ifndef INT16_MAX
# define INT16_MAX (32767)
#endif
#ifndef INT32_MIN
# define INT32_MIN (-2147483647-1)
#endif
#ifndef INT32_MAX
# define INT32_MAX (2147483647)
#endif
#ifndef UINT32_MIN
# define UINT32_MIN (0)
#endif
#ifndef UINT32_MAX
# define UINT32_MAX (4294967295U)
#endif
#ifndef INT64_MIN
# define INT64_MIN (-9223372036854775807-1)
#endif
#ifndef INT64_MAX
# define INT64_MAX (9223372036854775807)
#endif
#ifndef SIZE_MAX
# define SIZE_MAX ((size_t)-1)
#endif
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
#ifdef _MSC_VER
/* 'inline' is available only in C++ in MSVC */
# define inline __inline
# define force_inline __forceinline
# define noinline __declspec(noinline)
#elif defined __GNUC__ || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
# define inline __inline__
# define force_inline __inline__ __attribute__ ((__always_inline__))
# define noinline __attribute__((noinline))
#else
# ifndef force_inline
# define force_inline inline
# endif
# ifndef noinline
# define noinline
# endif
#endif
/* In libxul builds we don't ever want to export pixman symbols */
#if 1
#include "prcpucfg.h"
#ifdef HAVE_VISIBILITY_HIDDEN_ATTRIBUTE
#define CVISIBILITY_HIDDEN __attribute__((visibility("hidden")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
#define CVISIBILITY_HIDDEN __hidden
#else
#define CVISIBILITY_HIDDEN
#endif
/* In libxul builds we don't ever want to export cairo symbols */
#define PIXMAN_EXPORT extern CVISIBILITY_HIDDEN
#else
/* GCC visibility */
#if defined(__GNUC__) && __GNUC__ >= 4 && !defined(_WIN32)
# define PIXMAN_EXPORT __attribute__ ((visibility("default")))
/* Sun Studio 8 visibility */
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
# define PIXMAN_EXPORT __global
#else
# define PIXMAN_EXPORT
#endif
#endif
/* member offsets */
#define CONTAINER_OF(type, member, data) \
((type *)(((uint8_t *)data) - offsetof (type, member)))
/* TLS */
#if defined(PIXMAN_NO_TLS)
# define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \
static type name
# define PIXMAN_GET_THREAD_LOCAL(name) \
(&name)
#elif defined(TLS)
# define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \
static TLS type name
# define PIXMAN_GET_THREAD_LOCAL(name) \
(&name)
#elif defined(__MINGW32__) || defined(PIXMAN_USE_XP_DLL_TLS_WORKAROUND)
# define _NO_W32_PSEUDO_MODIFIERS
# include <windows.h>
#undef IN
#undef OUT
# define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \
static volatile int tls_ ## name ## _initialized = 0; \
static void *tls_ ## name ## _mutex = NULL; \
static unsigned tls_ ## name ## _index; \
\
static type * \
tls_ ## name ## _alloc (void) \
{ \
type *value = calloc (1, sizeof (type)); \
if (value) \
TlsSetValue (tls_ ## name ## _index, value); \
return value; \
} \
\
static force_inline type * \
tls_ ## name ## _get (void) \
{ \
type *value; \
if (!tls_ ## name ## _initialized) \
{ \
if (!tls_ ## name ## _mutex) \
{ \
void *mutex = CreateMutexA (NULL, 0, NULL); \
if (InterlockedCompareExchangePointer ( \
&tls_ ## name ## _mutex, mutex, NULL) != NULL) \
{ \
CloseHandle (mutex); \
} \
} \
WaitForSingleObject (tls_ ## name ## _mutex, 0xFFFFFFFF); \
if (!tls_ ## name ## _initialized) \
{ \
tls_ ## name ## _index = TlsAlloc (); \
tls_ ## name ## _initialized = 1; \
} \
ReleaseMutex (tls_ ## name ## _mutex); \
} \
if (tls_ ## name ## _index == 0xFFFFFFFF) \
return NULL; \
value = TlsGetValue (tls_ ## name ## _index); \
if (!value) \
value = tls_ ## name ## _alloc (); \
return value; \
}
# define PIXMAN_GET_THREAD_LOCAL(name) \
tls_ ## name ## _get ()
#elif defined(_MSC_VER)
# define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \
static __declspec(thread) type name
# define PIXMAN_GET_THREAD_LOCAL(name) \
(&name)
#elif defined(HAVE_PTHREAD_SETSPECIFIC)
#include <pthread.h>
# define PIXMAN_DEFINE_THREAD_LOCAL(type, name) \
static pthread_once_t tls_ ## name ## _once_control = PTHREAD_ONCE_INIT; \
static pthread_key_t tls_ ## name ## _key; \
\
static void \
tls_ ## name ## _destroy_value (void *value) \
{ \
free (value); \
} \
\
static void \
tls_ ## name ## _make_key (void) \
{ \
pthread_key_create (&tls_ ## name ## _key, \
tls_ ## name ## _destroy_value); \
} \
\
static type * \
tls_ ## name ## _alloc (void) \
{ \
type *value = calloc (1, sizeof (type)); \
if (value) \
pthread_setspecific (tls_ ## name ## _key, value); \
return value; \
} \
\
static force_inline type * \
tls_ ## name ## _get (void) \
{ \
type *value = NULL; \
if (pthread_once (&tls_ ## name ## _once_control, \
tls_ ## name ## _make_key) == 0) \
{ \
value = pthread_getspecific (tls_ ## name ## _key); \
if (!value) \
value = tls_ ## name ## _alloc (); \
} \
return value; \
}
# define PIXMAN_GET_THREAD_LOCAL(name) \
tls_ ## name ## _get ()
#else
# error "Unknown thread local support for this system. Pixman will not work with multiple threads. Define PIXMAN_NO_TLS to acknowledge and accept this limitation and compile pixman without thread-safety support."
#endif

View file

@ -0,0 +1,212 @@
/*
* 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
*
* 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 Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard 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 <math.h>
#include "pixman-private.h"
static force_inline double
coordinates_to_parameter (double x, double y, double angle)
{
double t;
t = atan2 (y, x) + angle;
while (t < 0)
t += 2 * M_PI;
while (t >= 2 * M_PI)
t -= 2 * M_PI;
return 1 - t * (1 / (2 * M_PI)); /* Scale t to [0, 1] and
* make rotation CCW
*/
}
static uint32_t *
conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
{
pixman_image_t *image = iter->image;
int x = iter->x;
int y = iter->y;
int width = iter->width;
uint32_t *buffer = iter->buffer;
gradient_t *gradient = (gradient_t *)image;
conical_gradient_t *conical = (conical_gradient_t *)image;
uint32_t *end = buffer + width;
pixman_gradient_walker_t walker;
pixman_bool_t affine = TRUE;
double cx = 1.;
double cy = 0.;
double cz = 0.;
double rx = x + 0.5;
double ry = y + 0.5;
double rz = 1.;
_pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
if (image->common.transform)
{
pixman_vector_t v;
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
if (!pixman_transform_point_3d (image->common.transform, &v))
return iter->buffer;
cx = image->common.transform->matrix[0][0] / 65536.;
cy = image->common.transform->matrix[1][0] / 65536.;
cz = image->common.transform->matrix[2][0] / 65536.;
rx = v.vector[0] / 65536.;
ry = v.vector[1] / 65536.;
rz = v.vector[2] / 65536.;
affine =
image->common.transform->matrix[2][0] == 0 &&
v.vector[2] == pixman_fixed_1;
}
if (affine)
{
rx -= conical->center.x / 65536.;
ry -= conical->center.y / 65536.;
while (buffer < end)
{
if (!mask || *mask++)
{
double t = coordinates_to_parameter (rx, ry, conical->angle);
*buffer = _pixman_gradient_walker_pixel (
&walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
}
++buffer;
rx += cx;
ry += cy;
}
}
else
{
while (buffer < end)
{
double x, y;
if (!mask || *mask++)
{
double t;
if (rz != 0)
{
x = rx / rz;
y = ry / rz;
}
else
{
x = y = 0.;
}
x -= conical->center.x / 65536.;
y -= conical->center.y / 65536.;
t = coordinates_to_parameter (x, y, conical->angle);
*buffer = _pixman_gradient_walker_pixel (
&walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
}
++buffer;
rx += cx;
ry += cy;
rz += cz;
}
}
iter->y++;
return iter->buffer;
}
static uint32_t *
conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
{
uint32_t *buffer = conical_get_scanline_narrow (iter, NULL);
pixman_expand_to_float (
(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
return buffer;
}
void
_pixman_conical_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
{
if (iter->iter_flags & ITER_NARROW)
iter->get_scanline = conical_get_scanline_narrow;
else
iter->get_scanline = conical_get_scanline_wide;
}
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_conical_gradient (const pixman_point_fixed_t * center,
pixman_fixed_t angle,
const pixman_gradient_stop_t *stops,
int n_stops)
{
pixman_image_t *image = _pixman_image_allocate ();
conical_gradient_t *conical;
if (!image)
return NULL;
conical = &image->conical;
if (!_pixman_init_gradient (&conical->common, stops, n_stops))
{
free (image);
return NULL;
}
angle = MOD (angle, pixman_int_to_fixed (360));
image->type = CONICAL;
conical->center = *center;
conical->angle = (pixman_fixed_to_double (angle) / 180.0) * M_PI;
return image;
}

View file

@ -0,0 +1,799 @@
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
*
* 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 SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* 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 <string.h>
#include <stdlib.h>
#if defined(USE_ARM_SIMD) && defined(_MSC_VER)
/* Needed for EXCEPTION_ILLEGAL_INSTRUCTION */
#include <windows.h>
#endif
#if defined(__APPLE__)
#include "TargetConditionals.h"
#endif
#include "pixman-private.h"
#ifdef USE_VMX
/* The CPU detection code needs to be in a file not compiled with
* "-maltivec -mabi=altivec", as gcc would try to save vector register
* across function calls causing SIGILL on cpus without Altivec/vmx.
*/
static pixman_bool_t initialized = FALSE;
static volatile pixman_bool_t have_vmx = TRUE;
#ifdef __APPLE__
#include <sys/sysctl.h>
static pixman_bool_t
pixman_have_vmx (void)
{
if (!initialized)
{
size_t length = sizeof(have_vmx);
int error =
sysctlbyname ("hw.optional.altivec", &have_vmx, &length, NULL, 0);
if (error)
have_vmx = FALSE;
initialized = TRUE;
}
return have_vmx;
}
#elif defined (__OpenBSD__)
#include <sys/param.h>
#include <sys/sysctl.h>
#include <machine/cpu.h>
static pixman_bool_t
pixman_have_vmx (void)
{
if (!initialized)
{
int mib[2] = { CTL_MACHDEP, CPU_ALTIVEC };
size_t length = sizeof(have_vmx);
int error =
sysctl (mib, 2, &have_vmx, &length, NULL, 0);
if (error != 0)
have_vmx = FALSE;
initialized = TRUE;
}
return have_vmx;
}
#elif defined (__linux__)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <linux/auxvec.h>
#include <asm/cputable.h>
static pixman_bool_t
pixman_have_vmx (void)
{
if (!initialized)
{
char fname[64];
unsigned long buf[64];
ssize_t count = 0;
pid_t pid;
int fd, i;
pid = getpid ();
snprintf (fname, sizeof(fname) - 1, "/proc/%d/auxv", pid);
fd = open (fname, O_RDONLY);
if (fd >= 0)
{
for (i = 0; i <= (count / sizeof(unsigned long)); i += 2)
{
/* Read more if buf is empty... */
if (i == (count / sizeof(unsigned long)))
{
count = read (fd, buf, sizeof(buf));
if (count <= 0)
break;
i = 0;
}
if (buf[i] == AT_HWCAP)
{
have_vmx = !!(buf[i + 1] & PPC_FEATURE_HAS_ALTIVEC);
initialized = TRUE;
break;
}
else if (buf[i] == AT_NULL)
{
break;
}
}
close (fd);
}
}
if (!initialized)
{
/* Something went wrong. Assume 'no' rather than playing
fragile tricks with catching SIGILL. */
have_vmx = FALSE;
initialized = TRUE;
}
return have_vmx;
}
#else /* !__APPLE__ && !__OpenBSD__ && !__linux__ */
#include <signal.h>
#include <setjmp.h>
static jmp_buf jump_env;
static void
vmx_test (int sig,
siginfo_t *si,
void * unused)
{
longjmp (jump_env, 1);
}
static pixman_bool_t
pixman_have_vmx (void)
{
struct sigaction sa, osa;
int jmp_result;
if (!initialized)
{
sa.sa_flags = SA_SIGINFO;
sigemptyset (&sa.sa_mask);
sa.sa_sigaction = vmx_test;
sigaction (SIGILL, &sa, &osa);
jmp_result = setjmp (jump_env);
if (jmp_result == 0)
{
asm volatile ( "vor 0, 0, 0" );
}
sigaction (SIGILL, &osa, NULL);
have_vmx = (jmp_result == 0);
initialized = TRUE;
}
return have_vmx;
}
#endif /* __APPLE__ */
#endif /* USE_VMX */
#if defined(USE_ARM_SIMD) || defined(USE_ARM_NEON) || defined(USE_ARM_IWMMXT)
#if defined(_MSC_VER)
#if defined(USE_ARM_SIMD)
extern int pixman_msvc_try_arm_simd_op ();
pixman_bool_t
pixman_have_arm_simd (void)
{
static pixman_bool_t initialized = FALSE;
static pixman_bool_t have_arm_simd = FALSE;
if (!initialized)
{
__try {
pixman_msvc_try_arm_simd_op ();
have_arm_simd = TRUE;
} __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION) {
have_arm_simd = FALSE;
}
initialized = TRUE;
}
return have_arm_simd;
}
#endif /* USE_ARM_SIMD */
#if defined(USE_ARM_NEON)
extern int pixman_msvc_try_arm_neon_op ();
pixman_bool_t
pixman_have_arm_neon (void)
{
static pixman_bool_t initialized = FALSE;
static pixman_bool_t have_arm_neon = FALSE;
if (!initialized)
{
__try
{
pixman_msvc_try_arm_neon_op ();
have_arm_neon = TRUE;
}
__except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION)
{
have_arm_neon = FALSE;
}
initialized = TRUE;
}
return have_arm_neon;
}
#endif /* USE_ARM_NEON */
#elif (defined (__APPLE__) && defined(TARGET_OS_IPHONE)) /* iOS (iPhone/iPad/iPod touch) */
/* Detection of ARM NEON on iOS is fairly simple because iOS binaries
* contain separate executable images for each processor architecture.
* So all we have to do is detect the armv7 architecture build. The
* operating system automatically runs the armv7 binary for armv7 devices
* and the armv6 binary for armv6 devices.
*/
pixman_bool_t
pixman_have_arm_simd (void)
{
#if defined(USE_ARM_SIMD)
return TRUE;
#else
return FALSE;
#endif
}
pixman_bool_t
pixman_have_arm_neon (void)
{
#if defined(USE_ARM_NEON) && defined(__ARM_NEON__)
/* This is an armv7 cpu build */
return TRUE;
#else
/* This is an armv6 cpu build */
return FALSE;
#endif
}
pixman_bool_t
pixman_have_arm_iwmmxt (void)
{
#if defined(USE_ARM_IWMMXT)
return FALSE;
#else
return FALSE;
#endif
}
#elif defined (__linux__) || defined(__ANDROID__) || defined(ANDROID) /* linux ELF or ANDROID */
static pixman_bool_t arm_has_v7 = FALSE;
static pixman_bool_t arm_has_v6 = FALSE;
static pixman_bool_t arm_has_vfp = FALSE;
static pixman_bool_t arm_has_neon = FALSE;
static pixman_bool_t arm_has_iwmmxt = FALSE;
static pixman_bool_t arm_tests_initialized = FALSE;
#if defined(__ANDROID__) || defined(ANDROID) /* Android device support */
static void
pixman_arm_read_auxv_or_cpu_features ()
{
char buf[1024];
char* pos;
const char* ver_token = "CPU architecture: ";
FILE* f = fopen("/proc/cpuinfo", "r");
if (!f) {
arm_tests_initialized = TRUE;
return;
}
fread(buf, sizeof(char), sizeof(buf), f);
fclose(f);
pos = strstr(buf, ver_token);
if (pos) {
char vchar = *(pos + strlen(ver_token));
if (vchar >= '0' && vchar <= '9') {
int ver = vchar - '0';
arm_has_v7 = ver >= 7;
arm_has_v6 = ver >= 6;
}
}
arm_has_neon = strstr(buf, "neon") != NULL;
arm_has_vfp = strstr(buf, "vfp") != NULL;
arm_has_iwmmxt = strstr(buf, "iwmmxt") != NULL;
arm_tests_initialized = TRUE;
}
#elif defined (__linux__) /* linux ELF */
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <elf.h>
static void
pixman_arm_read_auxv_or_cpu_features ()
{
int fd;
Elf32_auxv_t aux;
fd = open ("/proc/self/auxv", O_RDONLY);
if (fd >= 0)
{
while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t))
{
if (aux.a_type == AT_HWCAP)
{
uint32_t hwcap = aux.a_un.a_val;
/* hardcode these values to avoid depending on specific
* versions of the hwcap header, e.g. HWCAP_NEON
*/
arm_has_vfp = (hwcap & 64) != 0;
arm_has_iwmmxt = (hwcap & 512) != 0;
/* this flag is only present on kernel 2.6.29 */
arm_has_neon = (hwcap & 4096) != 0;
}
else if (aux.a_type == AT_PLATFORM)
{
const char *plat = (const char*) aux.a_un.a_val;
if (strncmp (plat, "v7l", 3) == 0)
{
arm_has_v7 = TRUE;
arm_has_v6 = TRUE;
}
else if (strncmp (plat, "v6l", 3) == 0)
{
arm_has_v6 = TRUE;
}
}
}
close (fd);
}
arm_tests_initialized = TRUE;
}
#endif /* Linux elf */
#if defined(USE_ARM_SIMD)
pixman_bool_t
pixman_have_arm_simd (void)
{
if (!arm_tests_initialized)
pixman_arm_read_auxv_or_cpu_features ();
return arm_has_v6;
}
#endif /* USE_ARM_SIMD */
#if defined(USE_ARM_NEON)
pixman_bool_t
pixman_have_arm_neon (void)
{
if (!arm_tests_initialized)
pixman_arm_read_auxv_or_cpu_features ();
return arm_has_neon;
}
#endif /* USE_ARM_NEON */
#if defined(USE_ARM_IWMMXT)
pixman_bool_t
pixman_have_arm_iwmmxt (void)
{
if (!arm_tests_initialized)
pixman_arm_read_auxv_or_cpu_features ();
return arm_has_iwmmxt;
}
#endif /* USE_ARM_IWMMXT */
#else /* !_MSC_VER && !Linux elf && !Android */
#define pixman_have_arm_simd() FALSE
#define pixman_have_arm_neon() FALSE
#define pixman_have_arm_iwmmxt() FALSE
#endif
#endif /* USE_ARM_SIMD || USE_ARM_NEON || USE_ARM_IWMMXT */
#if defined(USE_MIPS_DSPR2)
#if defined (__linux__) /* linux ELF */
pixman_bool_t
pixman_have_mips_dspr2 (void)
{
const char *search_string = "MIPS 74K";
const char *file_name = "/proc/cpuinfo";
/* Simple detection of MIPS DSP ASE (revision 2) at runtime for Linux.
* It is based on /proc/cpuinfo, which reveals hardware configuration
* to user-space applications. According to MIPS (early 2010), no similar
* facility is universally available on the MIPS architectures, so it's up
* to individual OSes to provide such.
*
* Only currently available MIPS core that supports DSPr2 is 74K.
*/
char cpuinfo_line[256];
FILE *f = NULL;
if ((f = fopen (file_name, "r")) == NULL)
return FALSE;
while (fgets (cpuinfo_line, sizeof (cpuinfo_line), f) != NULL)
{
if (strstr (cpuinfo_line, search_string) != NULL)
{
fclose (f);
return TRUE;
}
}
fclose (f);
/* Did not find string in the proc file. */
return FALSE;
}
#else /* linux ELF */
#define pixman_have_mips_dspr2() FALSE
#endif /* linux ELF */
#endif /* USE_MIPS_DSPR2 */
#if defined(USE_X86_MMX) || defined(USE_SSE2)
/* The CPU detection code needs to be in a file not compiled with
* "-mmmx -msse", as gcc would generate CMOV instructions otherwise
* that would lead to SIGILL instructions on old CPUs that don't have
* it.
*/
#if !defined(__amd64__) && !defined(__x86_64__) && !defined(_M_AMD64)
#ifdef HAVE_GETISAX
#include <sys/auxv.h>
#endif
typedef enum
{
NO_FEATURES = 0,
MMX = 0x1,
MMX_EXTENSIONS = 0x2,
SSE = 0x6,
SSE2 = 0x8,
CMOV = 0x10
} cpu_features_t;
static unsigned int
detect_cpu_features (void)
{
unsigned int features = 0;
unsigned int result = 0;
#ifdef HAVE_GETISAX
if (getisax (&result, 1))
{
if (result & AV_386_CMOV)
features |= CMOV;
if (result & AV_386_MMX)
features |= MMX;
if (result & AV_386_AMD_MMX)
features |= MMX_EXTENSIONS;
if (result & AV_386_SSE)
features |= SSE;
if (result & AV_386_SSE2)
features |= SSE2;
}
#else
char vendor[13];
#ifdef _MSC_VER
int vendor0 = 0, vendor1, vendor2;
#endif
vendor[0] = 0;
vendor[12] = 0;
#ifdef __GNUC__
/* see p. 118 of amd64 instruction set manual Vol3 */
/* We need to be careful about the handling of %ebx and
* %esp here. We can't declare either one as clobbered
* since they are special registers (%ebx is the "PIC
* register" holding an offset to global data, %esp the
* stack pointer), so we need to make sure they have their
* original values when we access the output operands.
*/
__asm__ (
"pushf\n"
"pop %%eax\n"
"mov %%eax, %%ecx\n"
"xor $0x00200000, %%eax\n"
"push %%eax\n"
"popf\n"
"pushf\n"
"pop %%eax\n"
"mov $0x0, %%edx\n"
"xor %%ecx, %%eax\n"
"jz 1f\n"
"mov $0x00000000, %%eax\n"
"push %%ebx\n"
"cpuid\n"
"mov %%ebx, %%eax\n"
"pop %%ebx\n"
"mov %%eax, %1\n"
"mov %%edx, %2\n"
"mov %%ecx, %3\n"
"mov $0x00000001, %%eax\n"
"push %%ebx\n"
"cpuid\n"
"pop %%ebx\n"
"1:\n"
"mov %%edx, %0\n"
: "=r" (result),
"=m" (vendor[0]),
"=m" (vendor[4]),
"=m" (vendor[8])
:
: "%eax", "%ecx", "%edx"
);
#elif defined (_MSC_VER)
_asm {
pushfd
pop eax
mov ecx, eax
xor eax, 00200000h
push eax
popfd
pushfd
pop eax
mov edx, 0
xor eax, ecx
jz nocpuid
mov eax, 0
push ebx
cpuid
mov eax, ebx
pop ebx
mov vendor0, eax
mov vendor1, edx
mov vendor2, ecx
mov eax, 1
push ebx
cpuid
pop ebx
nocpuid:
mov result, edx
}
memmove (vendor + 0, &vendor0, 4);
memmove (vendor + 4, &vendor1, 4);
memmove (vendor + 8, &vendor2, 4);
#else
# error unsupported compiler
#endif
features = 0;
if (result)
{
/* result now contains the standard feature bits */
if (result & (1 << 15))
features |= CMOV;
if (result & (1 << 23))
features |= MMX;
if (result & (1 << 25))
features |= SSE;
if (result & (1 << 26))
features |= SSE2;
if ((features & MMX) && !(features & SSE) &&
(strcmp (vendor, "AuthenticAMD") == 0 ||
strcmp (vendor, "Geode by NSC") == 0))
{
/* check for AMD MMX extensions */
#ifdef __GNUC__
__asm__ (
" push %%ebx\n"
" mov $0x80000000, %%eax\n"
" cpuid\n"
" xor %%edx, %%edx\n"
" cmp $0x1, %%eax\n"
" jge 2f\n"
" mov $0x80000001, %%eax\n"
" cpuid\n"
"2:\n"
" pop %%ebx\n"
" mov %%edx, %0\n"
: "=r" (result)
:
: "%eax", "%ecx", "%edx"
);
#elif defined _MSC_VER
_asm {
push ebx
mov eax, 80000000h
cpuid
xor edx, edx
cmp eax, 1
jge notamd
mov eax, 80000001h
cpuid
notamd:
pop ebx
mov result, edx
}
#endif
if (result & (1 << 22))
features |= MMX_EXTENSIONS;
}
}
#endif /* HAVE_GETISAX */
return features;
}
#ifdef USE_X86_MMX
static pixman_bool_t
pixman_have_mmx (void)
{
static pixman_bool_t initialized = FALSE;
static pixman_bool_t mmx_present;
if (!initialized)
{
unsigned int features = detect_cpu_features ();
mmx_present = (features & (MMX | MMX_EXTENSIONS)) == (MMX | MMX_EXTENSIONS);
initialized = TRUE;
}
return mmx_present;
}
#endif
#ifdef USE_SSE2
static pixman_bool_t
pixman_have_sse2 (void)
{
static pixman_bool_t initialized = FALSE;
static pixman_bool_t sse2_present;
if (!initialized)
{
unsigned int features = detect_cpu_features ();
sse2_present = (features & (MMX | MMX_EXTENSIONS | SSE | SSE2)) == (MMX | MMX_EXTENSIONS | SSE | SSE2);
initialized = TRUE;
}
return sse2_present;
}
#endif
#else /* __amd64__ */
#ifdef USE_X86_MMX
#define pixman_have_mmx() TRUE
#endif
#ifdef USE_SSE2
#define pixman_have_sse2() TRUE
#endif
#endif /* __amd64__ */
#endif
static pixman_bool_t
disabled (const char *name)
{
const char *env;
if ((env = getenv ("PIXMAN_DISABLE")))
{
do
{
const char *end;
int len;
if ((end = strchr (env, ' ')))
len = end - env;
else
len = strlen (env);
if (strlen (name) == len && strncmp (name, env, len) == 0)
{
printf ("pixman: Disabled %s implementation\n", name);
return TRUE;
}
env += len;
}
while (*env++);
}
return FALSE;
}
pixman_implementation_t *
_pixman_choose_implementation (void)
{
pixman_implementation_t *imp;
imp = _pixman_implementation_create_general();
if (!disabled ("fast"))
imp = _pixman_implementation_create_fast_path (imp);
#ifdef USE_X86_MMX
if (!disabled ("mmx") && pixman_have_mmx ())
imp = _pixman_implementation_create_mmx (imp);
#endif
#ifdef USE_SSE2
if (!disabled ("sse2") && pixman_have_sse2 ())
imp = _pixman_implementation_create_sse2 (imp);
#endif
#ifdef USE_ARM_SIMD
if (!disabled ("arm-simd") && pixman_have_arm_simd ())
imp = _pixman_implementation_create_arm_simd (imp);
#endif
#ifdef USE_ARM_IWMMXT
if (!disabled ("arm-iwmmxt") && pixman_have_arm_iwmmxt ())
imp = _pixman_implementation_create_mmx (imp);
#endif
#ifdef USE_ARM_NEON
if (!disabled ("arm-neon") && pixman_have_arm_neon ())
imp = _pixman_implementation_create_arm_neon (imp);
#endif
#ifdef USE_MIPS_DSPR2
if (!disabled ("mips-dspr2") && pixman_have_mips_dspr2 ())
imp = _pixman_implementation_create_mips_dspr2 (imp);
#endif
#ifdef USE_VMX
if (!disabled ("vmx") && pixman_have_vmx ())
imp = _pixman_implementation_create_vmx (imp);
#endif
imp = _pixman_implementation_create_noop (imp);
return imp;
}

View file

@ -0,0 +1,51 @@
#define R16_BITS 5
#define G16_BITS 6
#define B16_BITS 5
#define R16_SHIFT (B16_BITS + G16_BITS)
#define G16_SHIFT (B16_BITS)
#define B16_SHIFT 0
#define MASK 0xff
#define ONE_HALF 0x80
#define A_SHIFT 8 * 3
#define R_SHIFT 8 * 2
#define G_SHIFT 8
#define A_MASK 0xff000000
#define R_MASK 0xff0000
#define G_MASK 0xff00
#define RB_MASK 0xff00ff
#define AG_MASK 0xff00ff00
#define RB_ONE_HALF 0x800080
#define RB_MASK_PLUS_ONE 0x10000100
#define ALPHA_8(x) ((x) >> A_SHIFT)
#define RED_8(x) (((x) >> R_SHIFT) & MASK)
#define GREEN_8(x) (((x) >> G_SHIFT) & MASK)
#define BLUE_8(x) ((x) & MASK)
// This uses the same dithering technique that Skia does.
// It is essentially preturbing the lower bit based on the
// high bit
static inline uint16_t dither_32_to_16(uint32_t c)
{
uint8_t b = BLUE_8(c);
uint8_t g = GREEN_8(c);
uint8_t r = RED_8(c);
r = ((r << 1) - ((r >> (8 - R16_BITS) << (8 - R16_BITS)) | (r >> R16_BITS))) >> (8 - R16_BITS);
g = ((g << 1) - ((g >> (8 - G16_BITS) << (8 - G16_BITS)) | (g >> G16_BITS))) >> (8 - G16_BITS);
b = ((b << 1) - ((b >> (8 - B16_BITS) << (8 - B16_BITS)) | (b >> B16_BITS))) >> (8 - B16_BITS);
return ((r << R16_SHIFT) | (g << G16_SHIFT) | (b << B16_SHIFT));
}
static inline uint16_t dither_8888_to_0565(uint32_t color, pixman_bool_t toggle)
{
// alternate between a preturbed truncation and a regular truncation
if (toggle) {
return dither_32_to_16(color);
} else {
return convert_8888_to_0565(color);
}
}

View file

@ -0,0 +1,4 @@
#define PIXMAN_FB_ACCESSORS
#include "pixman-edge.c"

View file

@ -0,0 +1,183 @@
/*
* Copyright © 2004 Keith Packard
*
* 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 Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD 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.
*/
#ifndef rasterize_span
#endif
static void
RASTERIZE_EDGES (pixman_image_t *image,
pixman_edge_t *l,
pixman_edge_t *r,
pixman_fixed_t t,
pixman_fixed_t b)
{
pixman_fixed_t y = t;
uint32_t *line;
uint32_t *buf = (image)->bits.bits;
int stride = (image)->bits.rowstride;
int width = (image)->bits.width;
line = buf + pixman_fixed_to_int (y) * stride;
for (;;)
{
pixman_fixed_t lx;
pixman_fixed_t rx;
int lxi;
int rxi;
lx = l->x;
rx = r->x;
#if N_BITS == 1
/* For the non-antialiased case, round the coordinates up, in effect
* sampling just slightly to the left of the pixel. This is so that
* when the sample point lies exactly on the line, we round towards
* north-west.
*
* (The AA case does a similar adjustment in RENDER_SAMPLES_X)
*/
/* we cast to unsigned to get defined behaviour for overflow */
lx = (unsigned)lx + X_FRAC_FIRST(1) - pixman_fixed_e;
rx = (unsigned)rx + X_FRAC_FIRST(1) - pixman_fixed_e;
#endif
/* clip X */
if (lx < 0)
lx = 0;
if (pixman_fixed_to_int (rx) >= width)
#if N_BITS == 1
rx = pixman_int_to_fixed (width);
#else
/* Use the last pixel of the scanline, covered 100%.
* We can't use the first pixel following the scanline,
* because accessing it could result in a buffer overrun.
*/
rx = pixman_int_to_fixed (width) - 1;
#endif
/* Skip empty (or backwards) sections */
if (rx > lx)
{
/* Find pixel bounds for span */
lxi = pixman_fixed_to_int (lx);
rxi = pixman_fixed_to_int (rx);
#if N_BITS == 1
{
#define LEFT_MASK(x) \
(((x) & 0x1f) ? \
SCREEN_SHIFT_RIGHT (0xffffffff, (x) & 0x1f) : 0)
#define RIGHT_MASK(x) \
(((32 - (x)) & 0x1f) ? \
SCREEN_SHIFT_LEFT (0xffffffff, (32 - (x)) & 0x1f) : 0)
#define MASK_BITS(x,w,l,n,r) { \
n = (w); \
r = RIGHT_MASK ((x) + n); \
l = LEFT_MASK (x); \
if (l) { \
n -= 32 - ((x) & 0x1f); \
if (n < 0) { \
n = 0; \
l &= r; \
r = 0; \
} \
} \
n >>= 5; \
}
uint32_t *a = line;
uint32_t startmask;
uint32_t endmask;
int nmiddle;
int width = rxi - lxi;
int x = lxi;
a += x >> 5;
x &= 0x1f;
MASK_BITS (x, width, startmask, nmiddle, endmask);
if (startmask) {
WRITE(image, a, READ(image, a) | startmask);
a++;
}
while (nmiddle--)
WRITE(image, a++, 0xffffffff);
if (endmask)
WRITE(image, a, READ(image, a) | endmask);
}
#else
{
DEFINE_ALPHA(line,lxi);
int lxs;
int rxs;
/* Sample coverage for edge pixels */
lxs = RENDER_SAMPLES_X (lx, N_BITS);
rxs = RENDER_SAMPLES_X (rx, N_BITS);
/* Add coverage across row */
if (lxi == rxi)
{
ADD_ALPHA (rxs - lxs);
}
else
{
int xi;
ADD_ALPHA (N_X_FRAC(N_BITS) - lxs);
STEP_ALPHA;
for (xi = lxi + 1; xi < rxi; xi++)
{
ADD_ALPHA (N_X_FRAC(N_BITS));
STEP_ALPHA;
}
ADD_ALPHA (rxs);
}
}
#endif
}
if (y == b)
break;
#if N_BITS > 1
if (pixman_fixed_frac (y) != Y_FRAC_LAST(N_BITS))
{
RENDER_EDGE_STEP_SMALL (l);
RENDER_EDGE_STEP_SMALL (r);
y += STEP_Y_SMALL(N_BITS);
}
else
#endif
{
RENDER_EDGE_STEP_BIG (l);
RENDER_EDGE_STEP_BIG (r);
y += STEP_Y_BIG(N_BITS);
line += stride;
}
}
}
#undef rasterize_span

View file

@ -0,0 +1,385 @@
/*
* Copyright © 2004 Keith Packard
*
* 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 Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD 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 <string.h>
#include "pixman-private.h"
#include "pixman-accessor.h"
/*
* Step across a small sample grid gap
*/
#define RENDER_EDGE_STEP_SMALL(edge) \
{ \
edge->x += edge->stepx_small; \
edge->e += edge->dx_small; \
if (edge->e > 0) \
{ \
edge->e -= edge->dy; \
edge->x += edge->signdx; \
} \
}
/*
* Step across a large sample grid gap
*/
#define RENDER_EDGE_STEP_BIG(edge) \
{ \
edge->x += edge->stepx_big; \
edge->e += edge->dx_big; \
if (edge->e > 0) \
{ \
edge->e -= edge->dy; \
edge->x += edge->signdx; \
} \
}
#ifdef PIXMAN_FB_ACCESSORS
#define PIXMAN_RASTERIZE_EDGES pixman_rasterize_edges_accessors
#else
#define PIXMAN_RASTERIZE_EDGES pixman_rasterize_edges_no_accessors
#endif
/*
* 4 bit alpha
*/
#define N_BITS 4
#define RASTERIZE_EDGES rasterize_edges_4
#ifndef WORDS_BIGENDIAN
#define SHIFT_4(o) ((o) << 2)
#else
#define SHIFT_4(o) ((1 - (o)) << 2)
#endif
#define GET_4(x, o) (((x) >> SHIFT_4 (o)) & 0xf)
#define PUT_4(x, o, v) \
(((x) & ~(0xf << SHIFT_4 (o))) | (((v) & 0xf) << SHIFT_4 (o)))
#define DEFINE_ALPHA(line, x) \
uint8_t *__ap = (uint8_t *) line + ((x) >> 1); \
int __ao = (x) & 1
#define STEP_ALPHA ((__ap += __ao), (__ao ^= 1))
#define ADD_ALPHA(a) \
{ \
uint8_t __o = READ (image, __ap); \
uint8_t __a = (a) + GET_4 (__o, __ao); \
WRITE (image, __ap, PUT_4 (__o, __ao, __a | (0 - ((__a) >> 4)))); \
}
#include "pixman-edge-imp.h"
#undef ADD_ALPHA
#undef STEP_ALPHA
#undef DEFINE_ALPHA
#undef RASTERIZE_EDGES
#undef N_BITS
/*
* 1 bit alpha
*/
#define N_BITS 1
#define RASTERIZE_EDGES rasterize_edges_1
#include "pixman-edge-imp.h"
#undef RASTERIZE_EDGES
#undef N_BITS
/*
* 8 bit alpha
*/
static force_inline uint8_t
clip255 (int x)
{
if (x > 255)
return 255;
return x;
}
#define ADD_SATURATE_8(buf, val, length) \
do \
{ \
int i__ = (length); \
uint8_t *buf__ = (buf); \
int val__ = (val); \
\
while (i__--) \
{ \
WRITE (image, (buf__), clip255 (READ (image, (buf__)) + (val__))); \
(buf__)++; \
} \
} while (0)
/*
* We want to detect the case where we add the same value to a long
* span of pixels. The triangles on the end are filled in while we
* count how many sub-pixel scanlines contribute to the middle section.
*
* +--------------------------+
* fill_height =| \ /
* +------------------+
* |================|
* fill_start fill_end
*/
static void
rasterize_edges_8 (pixman_image_t *image,
pixman_edge_t * l,
pixman_edge_t * r,
pixman_fixed_t t,
pixman_fixed_t b)
{
pixman_fixed_t y = t;
uint32_t *line;
int fill_start = -1, fill_end = -1;
int fill_size = 0;
uint32_t *buf = (image)->bits.bits;
int stride = (image)->bits.rowstride;
int width = (image)->bits.width;
line = buf + pixman_fixed_to_int (y) * stride;
for (;;)
{
uint8_t *ap = (uint8_t *) line;
pixman_fixed_t lx, rx;
int lxi, rxi;
/* clip X */
lx = l->x;
if (lx < 0)
lx = 0;
rx = r->x;
if (pixman_fixed_to_int (rx) >= width)
{
/* Use the last pixel of the scanline, covered 100%.
* We can't use the first pixel following the scanline,
* because accessing it could result in a buffer overrun.
*/
rx = pixman_int_to_fixed (width) - 1;
}
/* Skip empty (or backwards) sections */
if (rx > lx)
{
int lxs, rxs;
/* Find pixel bounds for span. */
lxi = pixman_fixed_to_int (lx);
rxi = pixman_fixed_to_int (rx);
/* Sample coverage for edge pixels */
lxs = RENDER_SAMPLES_X (lx, 8);
rxs = RENDER_SAMPLES_X (rx, 8);
/* Add coverage across row */
if (lxi == rxi)
{
WRITE (image, ap + lxi,
clip255 (READ (image, ap + lxi) + rxs - lxs));
}
else
{
WRITE (image, ap + lxi,
clip255 (READ (image, ap + lxi) + N_X_FRAC (8) - lxs));
/* Move forward so that lxi/rxi is the pixel span */
lxi++;
/* Don't bother trying to optimize the fill unless
* the span is longer than 4 pixels. */
if (rxi - lxi > 4)
{
if (fill_start < 0)
{
fill_start = lxi;
fill_end = rxi;
fill_size++;
}
else
{
if (lxi >= fill_end || rxi < fill_start)
{
/* We're beyond what we saved, just fill it */
ADD_SATURATE_8 (ap + fill_start,
fill_size * N_X_FRAC (8),
fill_end - fill_start);
fill_start = lxi;
fill_end = rxi;
fill_size = 1;
}
else
{
/* Update fill_start */
if (lxi > fill_start)
{
ADD_SATURATE_8 (ap + fill_start,
fill_size * N_X_FRAC (8),
lxi - fill_start);
fill_start = lxi;
}
else if (lxi < fill_start)
{
ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8),
fill_start - lxi);
}
/* Update fill_end */
if (rxi < fill_end)
{
ADD_SATURATE_8 (ap + rxi,
fill_size * N_X_FRAC (8),
fill_end - rxi);
fill_end = rxi;
}
else if (fill_end < rxi)
{
ADD_SATURATE_8 (ap + fill_end,
N_X_FRAC (8),
rxi - fill_end);
}
fill_size++;
}
}
}
else
{
ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8), rxi - lxi);
}
WRITE (image, ap + rxi, clip255 (READ (image, ap + rxi) + rxs));
}
}
if (y == b)
{
/* We're done, make sure we clean up any remaining fill. */
if (fill_start != fill_end)
{
if (fill_size == N_Y_FRAC (8))
{
MEMSET_WRAPPED (image, ap + fill_start,
0xff, fill_end - fill_start);
}
else
{
ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8),
fill_end - fill_start);
}
}
break;
}
if (pixman_fixed_frac (y) != Y_FRAC_LAST (8))
{
RENDER_EDGE_STEP_SMALL (l);
RENDER_EDGE_STEP_SMALL (r);
y += STEP_Y_SMALL (8);
}
else
{
RENDER_EDGE_STEP_BIG (l);
RENDER_EDGE_STEP_BIG (r);
y += STEP_Y_BIG (8);
if (fill_start != fill_end)
{
if (fill_size == N_Y_FRAC (8))
{
MEMSET_WRAPPED (image, ap + fill_start,
0xff, fill_end - fill_start);
}
else
{
ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8),
fill_end - fill_start);
}
fill_start = fill_end = -1;
fill_size = 0;
}
line += stride;
}
}
}
#ifndef PIXMAN_FB_ACCESSORS
static
#endif
void
PIXMAN_RASTERIZE_EDGES (pixman_image_t *image,
pixman_edge_t * l,
pixman_edge_t * r,
pixman_fixed_t t,
pixman_fixed_t b)
{
switch (PIXMAN_FORMAT_BPP (image->bits.format))
{
case 1:
rasterize_edges_1 (image, l, r, t, b);
break;
case 4:
rasterize_edges_4 (image, l, r, t, b);
break;
case 8:
rasterize_edges_8 (image, l, r, t, b);
break;
default:
break;
}
}
#ifndef PIXMAN_FB_ACCESSORS
PIXMAN_EXPORT void
pixman_rasterize_edges (pixman_image_t *image,
pixman_edge_t * l,
pixman_edge_t * r,
pixman_fixed_t t,
pixman_fixed_t b)
{
return_if_fail (image->type == BITS);
return_if_fail (PIXMAN_FORMAT_TYPE (image->bits.format) == PIXMAN_TYPE_A);
if (image->bits.read_func || image->bits.write_func)
pixman_rasterize_edges_accessors (image, l, r, t, b);
else
pixman_rasterize_edges_no_accessors (image, l, r, t, b);
}
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,350 @@
/*
* Copyright 2012, Red Hat, Inc.
* Copyright 2012, Soren Sandmann
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Soren Sandmann <soren.sandmann@gmail.com>
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "pixman-private.h"
typedef double (* kernel_func_t) (double x);
typedef struct
{
pixman_kernel_t kernel;
kernel_func_t func;
double width;
} filter_info_t;
static double
impulse_kernel (double x)
{
return (x == 0.0)? 1.0 : 0.0;
}
static double
box_kernel (double x)
{
return 1;
}
static double
linear_kernel (double x)
{
return 1 - fabs (x);
}
static double
gaussian_kernel (double x)
{
#define SQRT2 (1.4142135623730950488016887242096980785696718753769480)
#define SIGMA (SQRT2 / 2.0)
return exp (- x * x / (2 * SIGMA * SIGMA)) / (SIGMA * sqrt (2.0 * M_PI));
}
static double
sinc (double x)
{
if (x == 0.0)
return 1.0;
else
return sin (M_PI * x) / (M_PI * x);
}
static double
lanczos (double x, int n)
{
return sinc (x) * sinc (x * (1.0 / n));
}
static double
lanczos2_kernel (double x)
{
return lanczos (x, 2);
}
static double
lanczos3_kernel (double x)
{
return lanczos (x, 3);
}
static double
nice_kernel (double x)
{
return lanczos3_kernel (x * 0.75);
}
static double
general_cubic (double x, double B, double C)
{
double ax = fabs(x);
if (ax < 1)
{
return ((12 - 9 * B - 6 * C) * ax * ax * ax +
(-18 + 12 * B + 6 * C) * ax * ax + (6 - 2 * B)) / 6;
}
else if (ax >= 1 && ax < 2)
{
return ((-B - 6 * C) * ax * ax * ax +
(6 * B + 30 * C) * ax * ax + (-12 * B - 48 * C) *
ax + (8 * B + 24 * C)) / 6;
}
else
{
return 0;
}
}
static double
cubic_kernel (double x)
{
/* This is the Mitchell-Netravali filter.
*
* (0.0, 0.5) would give us the Catmull-Rom spline,
* but that one seems to be indistinguishable from Lanczos2.
*/
return general_cubic (x, 1/3.0, 1/3.0);
}
static const filter_info_t filters[] =
{
{ PIXMAN_KERNEL_IMPULSE, impulse_kernel, 0.0 },
{ PIXMAN_KERNEL_BOX, box_kernel, 1.0 },
{ PIXMAN_KERNEL_LINEAR, linear_kernel, 2.0 },
{ PIXMAN_KERNEL_CUBIC, cubic_kernel, 4.0 },
{ PIXMAN_KERNEL_GAUSSIAN, gaussian_kernel, 6 * SIGMA },
{ PIXMAN_KERNEL_LANCZOS2, lanczos2_kernel, 4.0 },
{ PIXMAN_KERNEL_LANCZOS3, lanczos3_kernel, 6.0 },
{ PIXMAN_KERNEL_LANCZOS3_STRETCHED, nice_kernel, 8.0 },
};
/* This function scales @kernel2 by @scale, then
* aligns @x1 in @kernel1 with @x2 in @kernel2 and
* and integrates the product of the kernels across @width.
*
* This function assumes that the intervals are within
* the kernels in question. E.g., the caller must not
* try to integrate a linear kernel ouside of [-1:1]
*/
static double
integral (pixman_kernel_t kernel1, double x1,
pixman_kernel_t kernel2, double scale, double x2,
double width)
{
/* If the integration interval crosses zero, break it into
* two separate integrals. This ensures that filters such
* as LINEAR that are not differentiable at 0 will still
* integrate properly.
*/
if (x1 < 0 && x1 + width > 0)
{
return
integral (kernel1, x1, kernel2, scale, x2, - x1) +
integral (kernel1, 0, kernel2, scale, x2 - x1, width + x1);
}
else if (x2 < 0 && x2 + width > 0)
{
return
integral (kernel1, x1, kernel2, scale, x2, - x2) +
integral (kernel1, x1 - x2, kernel2, scale, 0, width + x2);
}
else if (kernel1 == PIXMAN_KERNEL_IMPULSE)
{
assert (width == 0.0);
return filters[kernel2].func (x2 * scale);
}
else if (kernel2 == PIXMAN_KERNEL_IMPULSE)
{
assert (width == 0.0);
return filters[kernel1].func (x1);
}
else
{
/* Integration via Simpson's rule */
#define N_SEGMENTS 128
#define SAMPLE(a1, a2) \
(filters[kernel1].func ((a1)) * filters[kernel2].func ((a2) * scale))
double s = 0.0;
double h = width / (double)N_SEGMENTS;
int i;
s = SAMPLE (x1, x2);
for (i = 1; i < N_SEGMENTS; i += 2)
{
double a1 = x1 + h * i;
double a2 = x2 + h * i;
s += 2 * SAMPLE (a1, a2);
if (i >= 2 && i < N_SEGMENTS - 1)
s += 4 * SAMPLE (a1, a2);
}
s += SAMPLE (x1 + width, x2 + width);
return h * s * (1.0 / 3.0);
}
}
static pixman_fixed_t *
create_1d_filter (int *width,
pixman_kernel_t reconstruct,
pixman_kernel_t sample,
double scale,
int n_phases)
{
pixman_fixed_t *params, *p;
double step;
double size;
int i;
size = scale * filters[sample].width + filters[reconstruct].width;
*width = ceil (size);
p = params = malloc (*width * n_phases * sizeof (pixman_fixed_t));
if (!params)
return NULL;
step = 1.0 / n_phases;
for (i = 0; i < n_phases; ++i)
{
double frac = step / 2.0 + i * step;
pixman_fixed_t new_total;
int x, x1, x2;
double total;
/* Sample convolution of reconstruction and sampling
* filter. See rounding.txt regarding the rounding
* and sample positions.
*/
x1 = ceil (frac - *width / 2.0 - 0.5);
x2 = x1 + *width;
total = 0;
for (x = x1; x < x2; ++x)
{
double pos = x + 0.5 - frac;
double rlow = - filters[reconstruct].width / 2.0;
double rhigh = rlow + filters[reconstruct].width;
double slow = pos - scale * filters[sample].width / 2.0;
double shigh = slow + scale * filters[sample].width;
double c = 0.0;
double ilow, ihigh;
if (rhigh >= slow && rlow <= shigh)
{
ilow = MAX (slow, rlow);
ihigh = MIN (shigh, rhigh);
c = integral (reconstruct, ilow,
sample, 1.0 / scale, ilow - pos,
ihigh - ilow);
}
total += c;
*p++ = (pixman_fixed_t)(c * 65535.0 + 0.5);
}
/* Normalize */
p -= *width;
total = 1 / total;
new_total = 0;
for (x = x1; x < x2; ++x)
{
pixman_fixed_t t = (*p) * total + 0.5;
new_total += t;
*p++ = t;
}
if (new_total != pixman_fixed_1)
*(p - *width / 2) += (pixman_fixed_1 - new_total);
}
return params;
}
/* Create the parameter list for a SEPARABLE_CONVOLUTION filter
* with the given kernels and scale parameters
*/
PIXMAN_EXPORT pixman_fixed_t *
pixman_filter_create_separable_convolution (int *n_values,
pixman_fixed_t scale_x,
pixman_fixed_t scale_y,
pixman_kernel_t reconstruct_x,
pixman_kernel_t reconstruct_y,
pixman_kernel_t sample_x,
pixman_kernel_t sample_y,
int subsample_bits_x,
int subsample_bits_y)
{
double sx = fabs (pixman_fixed_to_double (scale_x));
double sy = fabs (pixman_fixed_to_double (scale_y));
pixman_fixed_t *horz = NULL, *vert = NULL, *params = NULL;
int subsample_x, subsample_y;
int width, height;
subsample_x = (1 << subsample_bits_x);
subsample_y = (1 << subsample_bits_y);
horz = create_1d_filter (&width, reconstruct_x, sample_x, sx, subsample_x);
vert = create_1d_filter (&height, reconstruct_y, sample_y, sy, subsample_y);
if (!horz || !vert)
goto out;
*n_values = 4 + width * subsample_x + height * subsample_y;
params = malloc (*n_values * sizeof (pixman_fixed_t));
if (!params)
goto out;
params[0] = pixman_int_to_fixed (width);
params[1] = pixman_int_to_fixed (height);
params[2] = pixman_int_to_fixed (subsample_bits_x);
params[3] = pixman_int_to_fixed (subsample_bits_y);
memcpy (params + 4, horz,
width * subsample_x * sizeof (pixman_fixed_t));
memcpy (params + 4 + width * subsample_x, vert,
height * subsample_y * sizeof (pixman_fixed_t));
out:
free (horz);
free (vert);
return params;
}

View file

@ -0,0 +1,243 @@
/*
* 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"
static pixman_bool_t
general_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
{
pixman_image_t *image = iter->image;
if (image->type == LINEAR)
_pixman_linear_gradient_iter_init (image, iter);
else if (image->type == RADIAL)
_pixman_radial_gradient_iter_init (image, iter);
else if (image->type == CONICAL)
_pixman_conical_gradient_iter_init (image, iter);
else if (image->type == BITS)
_pixman_bits_image_src_iter_init (image, iter);
else if (image->type == SOLID)
_pixman_log_error (FUNC, "Solid image not handled by noop");
else
_pixman_log_error (FUNC, "Pixman bug: unknown image type\n");
return TRUE;
}
static pixman_bool_t
general_dest_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
{
if (iter->image->type == BITS)
{
_pixman_bits_image_dest_iter_init (iter->image, iter);
return TRUE;
}
else
{
_pixman_log_error (FUNC, "Trying to write to a non-writable image");
return FALSE;
}
}
typedef struct op_info_t op_info_t;
struct op_info_t
{
uint8_t src, dst;
};
#define ITER_IGNORE_BOTH \
(ITER_IGNORE_ALPHA | ITER_IGNORE_RGB | ITER_LOCALIZED_ALPHA)
static const op_info_t op_flags[PIXMAN_N_OPERATORS] =
{
/* Src Dst */
{ ITER_IGNORE_BOTH, ITER_IGNORE_BOTH }, /* CLEAR */
{ ITER_LOCALIZED_ALPHA, ITER_IGNORE_BOTH }, /* SRC */
{ ITER_IGNORE_BOTH, ITER_LOCALIZED_ALPHA }, /* DST */
{ 0, ITER_LOCALIZED_ALPHA }, /* OVER */
{ ITER_LOCALIZED_ALPHA, 0 }, /* OVER_REVERSE */
{ ITER_LOCALIZED_ALPHA, ITER_IGNORE_RGB }, /* IN */
{ ITER_IGNORE_RGB, ITER_LOCALIZED_ALPHA }, /* IN_REVERSE */
{ ITER_LOCALIZED_ALPHA, ITER_IGNORE_RGB }, /* OUT */
{ ITER_IGNORE_RGB, ITER_LOCALIZED_ALPHA }, /* OUT_REVERSE */
{ 0, 0 }, /* ATOP */
{ 0, 0 }, /* ATOP_REVERSE */
{ 0, 0 }, /* XOR */
{ ITER_LOCALIZED_ALPHA, ITER_LOCALIZED_ALPHA }, /* ADD */
{ 0, 0 }, /* SATURATE */
};
#define SCANLINE_BUFFER_LENGTH 8192
static void
general_composite_rect (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
PIXMAN_COMPOSITE_ARGS (info);
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;
pixman_iter_t src_iter, mask_iter, dest_iter;
pixman_combine_32_func_t compose;
pixman_bool_t component_alpha;
iter_flags_t narrow, src_iter_flags;
iter_flags_t rgb16;
int Bpp;
int i;
if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT) &&
(!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) &&
(dest_image->common.flags & FAST_PATH_NARROW_FORMAT))
{
narrow = ITER_NARROW;
Bpp = 4;
}
else
{
narrow = 0;
Bpp = 16;
}
// XXX: This special casing is bad. Ideally, we'd keep the general code general perhaps
// by having it deal more specifically with different intermediate formats
if (
(dest_image->common.flags & FAST_PATH_16_FORMAT && (src_image->type == LINEAR || src_image->type == RADIAL)) &&
( op == PIXMAN_OP_SRC ||
(op == PIXMAN_OP_OVER && (src_image->common.flags & FAST_PATH_IS_OPAQUE))
)
) {
rgb16 = ITER_16;
} else {
rgb16 = 0;
}
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;
if (!narrow)
{
/* To make sure there aren't any NANs in the buffers */
memset (src_buffer, 0, width * Bpp);
memset (mask_buffer, 0, width * Bpp);
memset (dest_buffer, 0, width * Bpp);
}
/* src iter */
src_iter_flags = narrow | op_flags[op].src | rgb16;
_pixman_implementation_src_iter_init (imp->toplevel, &src_iter, src_image,
src_x, src_y, width, height,
src_buffer, src_iter_flags, info->src_flags);
/* mask iter */
if ((src_iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) ==
(ITER_IGNORE_ALPHA | ITER_IGNORE_RGB))
{
/* If it doesn't matter what the source is, then it doesn't matter
* what the mask is
*/
mask_image = NULL;
}
component_alpha =
mask_image &&
mask_image->common.type == BITS &&
mask_image->common.component_alpha &&
PIXMAN_FORMAT_RGB (mask_image->bits.format);
_pixman_implementation_src_iter_init (
imp->toplevel, &mask_iter, mask_image, mask_x, mask_y, width, height,
mask_buffer, narrow | (component_alpha? 0 : ITER_IGNORE_RGB), info->mask_flags);
/* dest iter */
_pixman_implementation_dest_iter_init (
imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height,
dest_buffer, narrow | op_flags[op].dst | rgb16, info->dest_flags);
compose = _pixman_implementation_lookup_combiner (
imp->toplevel, op, component_alpha, narrow, !!rgb16);
for (i = 0; i < height; ++i)
{
uint32_t *s, *m, *d;
m = mask_iter.get_scanline (&mask_iter, NULL);
s = src_iter.get_scanline (&src_iter, m);
d = dest_iter.get_scanline (&dest_iter, NULL);
compose (imp->toplevel, op, d, s, m, width);
dest_iter.write_back (&dest_iter);
}
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 }
};
pixman_implementation_t *
_pixman_implementation_create_general (void)
{
pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path);
_pixman_setup_combiner_functions_16 (imp);
_pixman_setup_combiner_functions_32 (imp);
_pixman_setup_combiner_functions_float (imp);
imp->src_iter_init = general_src_iter_init;
imp->dest_iter_init = general_dest_iter_init;
return imp;
}

View file

@ -0,0 +1,670 @@
/*
* Copyright 2010, 2012, Soren Sandmann <sandmann@cs.au.dk>
* Copyright 2010, 2011, 2012, Red Hat, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Soren Sandmann <sandmann@cs.au.dk>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "pixman-private.h"
#include <stdlib.h>
typedef struct glyph_metrics_t glyph_metrics_t;
typedef struct glyph_t glyph_t;
#define TOMBSTONE ((glyph_t *)0x1)
/* XXX: These numbers are arbitrary---we've never done any measurements.
*/
#define N_GLYPHS_HIGH_WATER (16384)
#define N_GLYPHS_LOW_WATER (8192)
#define HASH_SIZE (2 * N_GLYPHS_HIGH_WATER)
#define HASH_MASK (HASH_SIZE - 1)
struct glyph_t
{
void * font_key;
void * glyph_key;
int origin_x;
int origin_y;
pixman_image_t * image;
pixman_link_t mru_link;
};
struct pixman_glyph_cache_t
{
int n_glyphs;
int n_tombstones;
int freeze_count;
pixman_list_t mru;
glyph_t * glyphs[HASH_SIZE];
};
static void
free_glyph (glyph_t *glyph)
{
pixman_list_unlink (&glyph->mru_link);
pixman_image_unref (glyph->image);
free (glyph);
}
static unsigned int
hash (const void *font_key, const void *glyph_key)
{
size_t key = (size_t)font_key + (size_t)glyph_key;
/* This hash function is based on one found on Thomas Wang's
* web page at
*
* http://www.concentric.net/~Ttwang/tech/inthash.htm
*
*/
key = (key << 15) - key - 1;
key = key ^ (key >> 12);
key = key + (key << 2);
key = key ^ (key >> 4);
key = key + (key << 3) + (key << 11);
key = key ^ (key >> 16);
return key;
}
static glyph_t *
lookup_glyph (pixman_glyph_cache_t *cache,
void *font_key,
void *glyph_key)
{
unsigned idx;
glyph_t *g;
idx = hash (font_key, glyph_key);
while ((g = cache->glyphs[idx++ & HASH_MASK]))
{
if (g != TOMBSTONE &&
g->font_key == font_key &&
g->glyph_key == glyph_key)
{
return g;
}
}
return NULL;
}
static void
insert_glyph (pixman_glyph_cache_t *cache,
glyph_t *glyph)
{
unsigned idx;
glyph_t **loc;
idx = hash (glyph->font_key, glyph->glyph_key);
/* Note: we assume that there is room in the table. If there isn't,
* this will be an infinite loop.
*/
do
{
loc = &cache->glyphs[idx++ & HASH_MASK];
} while (*loc && *loc != TOMBSTONE);
if (*loc == TOMBSTONE)
cache->n_tombstones--;
cache->n_glyphs++;
*loc = glyph;
}
static void
remove_glyph (pixman_glyph_cache_t *cache,
glyph_t *glyph)
{
unsigned idx;
idx = hash (glyph->font_key, glyph->glyph_key);
while (cache->glyphs[idx & HASH_MASK] != glyph)
idx++;
cache->glyphs[idx & HASH_MASK] = TOMBSTONE;
cache->n_tombstones++;
cache->n_glyphs--;
/* Eliminate tombstones if possible */
if (cache->glyphs[(idx + 1) & HASH_MASK] == NULL)
{
while (cache->glyphs[idx & HASH_MASK] == TOMBSTONE)
{
cache->glyphs[idx & HASH_MASK] = NULL;
cache->n_tombstones--;
idx--;
}
}
}
static void
clear_table (pixman_glyph_cache_t *cache)
{
int i;
for (i = 0; i < HASH_SIZE; ++i)
{
glyph_t *glyph = cache->glyphs[i];
if (glyph && glyph != TOMBSTONE)
free_glyph (glyph);
cache->glyphs[i] = NULL;
}
cache->n_glyphs = 0;
cache->n_tombstones = 0;
}
PIXMAN_EXPORT pixman_glyph_cache_t *
pixman_glyph_cache_create (void)
{
pixman_glyph_cache_t *cache;
if (!(cache = malloc (sizeof *cache)))
return NULL;
memset (cache->glyphs, 0, sizeof (cache->glyphs));
cache->n_glyphs = 0;
cache->n_tombstones = 0;
cache->freeze_count = 0;
pixman_list_init (&cache->mru);
return cache;
}
PIXMAN_EXPORT void
pixman_glyph_cache_destroy (pixman_glyph_cache_t *cache)
{
return_if_fail (cache->freeze_count == 0);
clear_table (cache);
free (cache);
}
PIXMAN_EXPORT void
pixman_glyph_cache_freeze (pixman_glyph_cache_t *cache)
{
cache->freeze_count++;
}
PIXMAN_EXPORT void
pixman_glyph_cache_thaw (pixman_glyph_cache_t *cache)
{
if (--cache->freeze_count == 0 &&
cache->n_glyphs + cache->n_tombstones > N_GLYPHS_HIGH_WATER)
{
if (cache->n_tombstones > N_GLYPHS_HIGH_WATER)
{
/* More than half the entries are
* tombstones. Just dump the whole table.
*/
clear_table (cache);
}
while (cache->n_glyphs > N_GLYPHS_LOW_WATER)
{
glyph_t *glyph = CONTAINER_OF (glyph_t, mru_link, cache->mru.tail);
remove_glyph (cache, glyph);
free_glyph (glyph);
}
}
}
PIXMAN_EXPORT const void *
pixman_glyph_cache_lookup (pixman_glyph_cache_t *cache,
void *font_key,
void *glyph_key)
{
return lookup_glyph (cache, font_key, glyph_key);
}
PIXMAN_EXPORT const void *
pixman_glyph_cache_insert (pixman_glyph_cache_t *cache,
void *font_key,
void *glyph_key,
int origin_x,
int origin_y,
pixman_image_t *image)
{
glyph_t *glyph;
int32_t width, height;
return_val_if_fail (cache->freeze_count > 0, NULL);
return_val_if_fail (image->type == BITS, NULL);
width = image->bits.width;
height = image->bits.height;
if (cache->n_glyphs >= HASH_SIZE)
return NULL;
if (!(glyph = malloc (sizeof *glyph)))
return NULL;
glyph->font_key = font_key;
glyph->glyph_key = glyph_key;
glyph->origin_x = origin_x;
glyph->origin_y = origin_y;
if (!(glyph->image = pixman_image_create_bits (
image->bits.format, width, height, NULL, -1)))
{
free (glyph);
return NULL;
}
pixman_image_composite32 (PIXMAN_OP_SRC,
image, NULL, glyph->image, 0, 0, 0, 0, 0, 0,
width, height);
if (PIXMAN_FORMAT_A (glyph->image->bits.format) != 0 &&
PIXMAN_FORMAT_RGB (glyph->image->bits.format) != 0)
{
pixman_image_set_component_alpha (glyph->image, TRUE);
}
pixman_list_prepend (&cache->mru, &glyph->mru_link);
_pixman_image_validate (glyph->image);
insert_glyph (cache, glyph);
return glyph;
}
PIXMAN_EXPORT void
pixman_glyph_cache_remove (pixman_glyph_cache_t *cache,
void *font_key,
void *glyph_key)
{
glyph_t *glyph;
if ((glyph = lookup_glyph (cache, font_key, glyph_key)))
{
remove_glyph (cache, glyph);
free_glyph (glyph);
}
}
PIXMAN_EXPORT void
pixman_glyph_get_extents (pixman_glyph_cache_t *cache,
int n_glyphs,
pixman_glyph_t *glyphs,
pixman_box32_t *extents)
{
int i;
extents->x1 = extents->y1 = INT32_MAX;
extents->x2 = extents->y2 = INT32_MIN;
for (i = 0; i < n_glyphs; ++i)
{
glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
int x1, y1, x2, y2;
x1 = glyphs[i].x - glyph->origin_x;
y1 = glyphs[i].y - glyph->origin_y;
x2 = glyphs[i].x - glyph->origin_x + glyph->image->bits.width;
y2 = glyphs[i].y - glyph->origin_y + glyph->image->bits.height;
if (x1 < extents->x1)
extents->x1 = x1;
if (y1 < extents->y1)
extents->y1 = y1;
if (x2 > extents->x2)
extents->x2 = x2;
if (y2 > extents->y2)
extents->y2 = y2;
}
}
/* This function returns a format that is suitable for use as a mask for the
* set of glyphs in question.
*/
PIXMAN_EXPORT pixman_format_code_t
pixman_glyph_get_mask_format (pixman_glyph_cache_t *cache,
int n_glyphs,
const pixman_glyph_t *glyphs)
{
pixman_format_code_t format = PIXMAN_a1;
int i;
for (i = 0; i < n_glyphs; ++i)
{
const glyph_t *glyph = glyphs[i].glyph;
pixman_format_code_t glyph_format = glyph->image->bits.format;
if (PIXMAN_FORMAT_TYPE (glyph_format) == PIXMAN_TYPE_A)
{
if (PIXMAN_FORMAT_A (glyph_format) > PIXMAN_FORMAT_A (format))
format = glyph_format;
}
else
{
return PIXMAN_a8r8g8b8;
}
}
return format;
}
static pixman_bool_t
box32_intersect (pixman_box32_t *dest,
const pixman_box32_t *box1,
const pixman_box32_t *box2)
{
dest->x1 = MAX (box1->x1, box2->x1);
dest->y1 = MAX (box1->y1, box2->y1);
dest->x2 = MIN (box1->x2, box2->x2);
dest->y2 = MIN (box1->y2, box2->y2);
return dest->x2 > dest->x1 && dest->y2 > dest->y1;
}
PIXMAN_EXPORT void
pixman_composite_glyphs_no_mask (pixman_op_t op,
pixman_image_t *src,
pixman_image_t *dest,
int32_t src_x,
int32_t src_y,
int32_t dest_x,
int32_t dest_y,
pixman_glyph_cache_t *cache,
int n_glyphs,
const pixman_glyph_t *glyphs)
{
pixman_region32_t region;
pixman_format_code_t glyph_format = PIXMAN_null;
uint32_t glyph_flags = 0;
pixman_format_code_t dest_format;
uint32_t dest_flags;
pixman_composite_func_t func = NULL;
pixman_implementation_t *implementation = NULL;
pixman_composite_info_t info;
int i;
_pixman_image_validate (src);
_pixman_image_validate (dest);
dest_format = dest->common.extended_format_code;
dest_flags = dest->common.flags;
pixman_region32_init (&region);
if (!_pixman_compute_composite_region32 (
&region,
src, NULL, dest,
src_x - dest_x, src_y - dest_y, 0, 0, 0, 0,
dest->bits.width, dest->bits.height))
{
goto out;
}
info.op = op;
info.src_image = src;
info.dest_image = dest;
info.src_flags = src->common.flags;
info.dest_flags = dest->common.flags;
for (i = 0; i < n_glyphs; ++i)
{
glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
pixman_image_t *glyph_img = glyph->image;
pixman_box32_t glyph_box;
pixman_box32_t *pbox;
uint32_t extra = FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
pixman_box32_t composite_box;
int n;
glyph_box.x1 = dest_x + glyphs[i].x - glyph->origin_x;
glyph_box.y1 = dest_y + glyphs[i].y - glyph->origin_y;
glyph_box.x2 = glyph_box.x1 + glyph->image->bits.width;
glyph_box.y2 = glyph_box.y1 + glyph->image->bits.height;
pbox = pixman_region32_rectangles (&region, &n);
info.mask_image = glyph_img;
while (n--)
{
if (box32_intersect (&composite_box, pbox, &glyph_box))
{
if (glyph_img->common.extended_format_code != glyph_format ||
glyph_img->common.flags != glyph_flags)
{
glyph_format = glyph_img->common.extended_format_code;
glyph_flags = glyph_img->common.flags;
_pixman_implementation_lookup_composite (
get_implementation(), op,
src->common.extended_format_code, src->common.flags,
glyph_format, glyph_flags | extra,
dest_format, dest_flags,
&implementation, &func);
}
info.src_x = src_x + composite_box.x1 - dest_x;
info.src_y = src_y + composite_box.y1 - dest_y;
info.mask_x = composite_box.x1 - (dest_x + glyphs[i].x - glyph->origin_x);
info.mask_y = composite_box.y1 - (dest_y + glyphs[i].y - glyph->origin_y);
info.dest_x = composite_box.x1;
info.dest_y = composite_box.y1;
info.width = composite_box.x2 - composite_box.x1;
info.height = composite_box.y2 - composite_box.y1;
info.mask_flags = glyph_flags;
func (implementation, &info);
}
pbox++;
}
pixman_list_move_to_front (&cache->mru, &glyph->mru_link);
}
out:
pixman_region32_fini (&region);
}
static void
add_glyphs (pixman_glyph_cache_t *cache,
pixman_image_t *dest,
int off_x, int off_y,
int n_glyphs, const pixman_glyph_t *glyphs)
{
pixman_format_code_t glyph_format = PIXMAN_null;
uint32_t glyph_flags = 0;
pixman_composite_func_t func = NULL;
pixman_implementation_t *implementation = NULL;
pixman_format_code_t dest_format;
uint32_t dest_flags;
pixman_box32_t dest_box;
pixman_composite_info_t info;
pixman_image_t *white_img = NULL;
pixman_bool_t white_src = FALSE;
int i;
_pixman_image_validate (dest);
dest_format = dest->common.extended_format_code;
dest_flags = dest->common.flags;
info.op = PIXMAN_OP_ADD;
info.dest_image = dest;
info.src_x = 0;
info.src_y = 0;
info.dest_flags = dest_flags;
dest_box.x1 = 0;
dest_box.y1 = 0;
dest_box.x2 = dest->bits.width;
dest_box.y2 = dest->bits.height;
for (i = 0; i < n_glyphs; ++i)
{
glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
pixman_image_t *glyph_img = glyph->image;
pixman_box32_t glyph_box;
pixman_box32_t composite_box;
if (glyph_img->common.extended_format_code != glyph_format ||
glyph_img->common.flags != glyph_flags)
{
pixman_format_code_t src_format, mask_format;
glyph_format = glyph_img->common.extended_format_code;
glyph_flags = glyph_img->common.flags;
if (glyph_format == dest->bits.format)
{
src_format = glyph_format;
mask_format = PIXMAN_null;
info.src_flags = glyph_flags | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
info.mask_flags = FAST_PATH_IS_OPAQUE;
info.mask_image = NULL;
white_src = FALSE;
}
else
{
if (!white_img)
{
static const pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
if (!(white_img = pixman_image_create_solid_fill (&white)))
goto out;
_pixman_image_validate (white_img);
}
src_format = PIXMAN_solid;
mask_format = glyph_format;
info.src_flags = white_img->common.flags;
info.mask_flags = glyph_flags | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
info.src_image = white_img;
white_src = TRUE;
}
_pixman_implementation_lookup_composite (
get_implementation(), PIXMAN_OP_ADD,
src_format, info.src_flags,
mask_format, info.mask_flags,
dest_format, dest_flags,
&implementation, &func);
}
glyph_box.x1 = glyphs[i].x - glyph->origin_x + off_x;
glyph_box.y1 = glyphs[i].y - glyph->origin_y + off_y;
glyph_box.x2 = glyph_box.x1 + glyph->image->bits.width;
glyph_box.y2 = glyph_box.y1 + glyph->image->bits.height;
if (box32_intersect (&composite_box, &glyph_box, &dest_box))
{
int src_x = composite_box.x1 - glyph_box.x1;
int src_y = composite_box.y1 - glyph_box.y1;
if (white_src)
info.mask_image = glyph_img;
else
info.src_image = glyph_img;
info.mask_x = info.src_x = src_x;
info.mask_y = info.src_y = src_y;
info.dest_x = composite_box.x1;
info.dest_y = composite_box.y1;
info.width = composite_box.x2 - composite_box.x1;
info.height = composite_box.y2 - composite_box.y1;
func (implementation, &info);
pixman_list_move_to_front (&cache->mru, &glyph->mru_link);
}
}
out:
if (white_img)
pixman_image_unref (white_img);
}
/* Conceptually, for each glyph, (white IN glyph) is PIXMAN_OP_ADDed to an
* infinitely big mask image at the position such that the glyph origin point
* is positioned at the (glyphs[i].x, glyphs[i].y) point.
*
* Then (mask_x, mask_y) in the infinite mask and (src_x, src_y) in the source
* image are both aligned with (dest_x, dest_y) in the destination image. Then
* these three images are composited within the
*
* (dest_x, dest_y, dst_x + width, dst_y + height)
*
* rectangle.
*
* TODO:
* - Trim the mask to the destination clip/image?
* - Trim composite region based on sources, when the op ignores 0s.
*/
PIXMAN_EXPORT void
pixman_composite_glyphs (pixman_op_t op,
pixman_image_t *src,
pixman_image_t *dest,
pixman_format_code_t mask_format,
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,
pixman_glyph_cache_t *cache,
int n_glyphs,
const pixman_glyph_t *glyphs)
{
pixman_image_t *mask;
if (!(mask = pixman_image_create_bits (mask_format, width, height, NULL, -1)))
return;
if (PIXMAN_FORMAT_A (mask_format) != 0 &&
PIXMAN_FORMAT_RGB (mask_format) != 0)
{
pixman_image_set_component_alpha (mask, TRUE);
}
add_glyphs (cache, mask, - mask_x, - mask_y, n_glyphs, glyphs);
pixman_image_composite32 (op, src, mask, dest,
src_x, src_y,
0, 0,
dest_x, dest_y,
width, height);
pixman_image_unref (mask);
}

View file

@ -0,0 +1,172 @@
/*
*
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
* 2005 Lars Knoll & Zack Rusin, Trolltech
*
* 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 Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard 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 "pixman-private.h"
void
_pixman_gradient_walker_init (pixman_gradient_walker_t *walker,
gradient_t * gradient,
pixman_repeat_t repeat)
{
walker->num_stops = gradient->n_stops;
walker->stops = gradient->stops;
walker->left_x = 0;
walker->right_x = 0x10000;
walker->stepper = 0;
walker->left_ag = 0;
walker->left_rb = 0;
walker->right_ag = 0;
walker->right_rb = 0;
walker->repeat = repeat;
walker->need_reset = TRUE;
}
static void
gradient_walker_reset (pixman_gradient_walker_t *walker,
pixman_fixed_48_16_t pos)
{
int32_t x, left_x, right_x;
pixman_color_t *left_c, *right_c;
int n, count = walker->num_stops;
pixman_gradient_stop_t *stops = walker->stops;
if (walker->repeat == PIXMAN_REPEAT_NORMAL)
{
x = (int32_t)pos & 0xffff;
}
else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
{
x = (int32_t)pos & 0xffff;
if ((int32_t)pos & 0x10000)
x = 0x10000 - x;
}
else
{
x = pos;
}
for (n = 0; n < count; n++)
{
if (x < stops[n].x)
break;
}
left_x = stops[n - 1].x;
left_c = &stops[n - 1].color;
right_x = stops[n].x;
right_c = &stops[n].color;
if (walker->repeat == PIXMAN_REPEAT_NORMAL)
{
left_x += (pos - x);
right_x += (pos - x);
}
else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
{
if ((int32_t)pos & 0x10000)
{
pixman_color_t *tmp_c;
int32_t tmp_x;
tmp_x = 0x10000 - right_x;
right_x = 0x10000 - left_x;
left_x = tmp_x;
tmp_c = right_c;
right_c = left_c;
left_c = tmp_c;
x = 0x10000 - x;
}
left_x += (pos - x);
right_x += (pos - x);
}
else if (walker->repeat == PIXMAN_REPEAT_NONE)
{
if (n == 0)
right_c = left_c;
else if (n == count)
left_c = right_c;
}
walker->left_x = left_x;
walker->right_x = right_x;
walker->left_ag = ((left_c->alpha >> 8) << 16) | (left_c->green >> 8);
walker->left_rb = ((left_c->red & 0xff00) << 8) | (left_c->blue >> 8);
walker->right_ag = ((right_c->alpha >> 8) << 16) | (right_c->green >> 8);
walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8);
if (walker->left_x == walker->right_x ||
(walker->left_ag == walker->right_ag &&
walker->left_rb == walker->right_rb))
{
walker->stepper = 0;
}
else
{
int32_t width = right_x - left_x;
walker->stepper = ((1 << 24) + width / 2) / width;
}
walker->need_reset = FALSE;
}
uint32_t
_pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
pixman_fixed_48_16_t x)
{
int dist, idist;
uint32_t t1, t2, a, color;
if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
gradient_walker_reset (walker, x);
dist = ((int)(x - walker->left_x) * walker->stepper) >> 16;
idist = 256 - dist;
/* combined INTERPOLATE and premultiply */
t1 = walker->left_rb * idist + walker->right_rb * dist;
t1 = (t1 >> 8) & 0xff00ff;
t2 = walker->left_ag * idist + walker->right_ag * dist;
t2 &= 0xff00ff00;
color = t2 & 0xff000000;
a = t2 >> 24;
t1 = t1 * a + 0x800080;
t1 = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8;
t2 = (t2 >> 8) * a + 0x800080;
t2 = (t2 + ((t2 >> 8) & 0xff00ff));
return (color | (t1 & 0xff00ff) | (t2 & 0xff00));
}

View file

@ -0,0 +1,967 @@
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
*
* 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 SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* 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 <stdio.h>
#include <string.h>
#include <assert.h>
#include "pixman-private.h"
static const pixman_color_t transparent_black = { 0, 0, 0, 0 };
/**
** bug 1293598 - clean up every pointer after free to avoid
** "dereferencing freed memory" problem
**/
#define PIXMAN_POSION
static void
free_memory (void** p)
{
#ifdef PIXMAN_POISON
if (*p) {
#endif
free (*p);
#ifdef PIXMAN_POISON
*p = NULL;
}
#endif
}
static void
gradient_property_changed (pixman_image_t *image)
{
gradient_t *gradient = &image->gradient;
int n = gradient->n_stops;
pixman_gradient_stop_t *stops = gradient->stops;
pixman_gradient_stop_t *begin = &(gradient->stops[-1]);
pixman_gradient_stop_t *end = &(gradient->stops[n]);
switch (gradient->common.repeat)
{
default:
case PIXMAN_REPEAT_NONE:
begin->x = INT32_MIN;
begin->color = transparent_black;
end->x = INT32_MAX;
end->color = transparent_black;
break;
case PIXMAN_REPEAT_NORMAL:
begin->x = stops[n - 1].x - pixman_fixed_1;
begin->color = stops[n - 1].color;
end->x = stops[0].x + pixman_fixed_1;
end->color = stops[0].color;
break;
case PIXMAN_REPEAT_REFLECT:
begin->x = - stops[0].x;
begin->color = stops[0].color;
end->x = pixman_int_to_fixed (2) - stops[n - 1].x;
end->color = stops[n - 1].color;
break;
case PIXMAN_REPEAT_PAD:
begin->x = INT32_MIN;
begin->color = stops[0].color;
end->x = INT32_MAX;
end->color = stops[n - 1].color;
break;
}
}
pixman_bool_t
_pixman_init_gradient (gradient_t * gradient,
const pixman_gradient_stop_t *stops,
int n_stops)
{
return_val_if_fail (n_stops > 0, FALSE);
/* We allocate two extra stops, one before the beginning of the stop list,
* and one after the end. These stops are initialized to whatever color
* would be used for positions outside the range of the stop list.
*
* This saves a bit of computation in the gradient walker.
*
* The pointer we store in the gradient_t struct still points to the
* first user-supplied struct, so when freeing, we will have to
* subtract one.
*/
gradient->stops =
pixman_malloc_ab (n_stops + 2, sizeof (pixman_gradient_stop_t));
if (!gradient->stops)
return FALSE;
gradient->stops += 1;
memcpy (gradient->stops, stops, n_stops * sizeof (pixman_gradient_stop_t));
gradient->n_stops = n_stops;
gradient->common.property_changed = gradient_property_changed;
return TRUE;
}
void
_pixman_image_init (pixman_image_t *image)
{
image_common_t *common = &image->common;
pixman_region32_init (&common->clip_region);
common->alpha_count = 0;
common->have_clip_region = FALSE;
common->clip_sources = FALSE;
common->transform = NULL;
common->repeat = PIXMAN_REPEAT_NONE;
common->filter = PIXMAN_FILTER_NEAREST;
common->filter_params = NULL;
common->n_filter_params = 0;
common->alpha_map = NULL;
common->component_alpha = FALSE;
common->ref_count = 1;
common->property_changed = NULL;
common->client_clip = FALSE;
common->destroy_func = NULL;
common->destroy_data = NULL;
common->dirty = TRUE;
}
pixman_bool_t
_pixman_image_fini (pixman_image_t *image)
{
image_common_t *common = (image_common_t *)image;
common->ref_count--;
if (common->ref_count == 0)
{
if (image->common.destroy_func)
image->common.destroy_func (image, image->common.destroy_data);
pixman_region32_fini (&common->clip_region);
free_memory (&common->transform);
free_memory (&common->filter_params);
if (common->alpha_map)
pixman_image_unref ((pixman_image_t *)common->alpha_map);
if (image->type == LINEAR ||
image->type == RADIAL ||
image->type == CONICAL)
{
if (image->gradient.stops)
{
/* See _pixman_init_gradient() for an explanation of the - 1 */
void *addr = image->gradient.stops - 1;
free_memory (&addr);
}
/* This will trigger if someone adds a property_changed
* method to the linear/radial/conical gradient overwriting
* the general one.
*/
assert (
image->common.property_changed == gradient_property_changed);
}
if (image->type == BITS && image->bits.free_me) {
free_memory (&image->bits.free_me);
image->bits.bits = NULL;
}
return TRUE;
}
return FALSE;
}
pixman_image_t *
_pixman_image_allocate (void)
{
pixman_image_t *image = malloc (sizeof (pixman_image_t));
if (image)
_pixman_image_init (image);
return image;
}
static void
image_property_changed (pixman_image_t *image)
{
image->common.dirty = TRUE;
}
/* Ref Counting */
PIXMAN_EXPORT pixman_image_t *
pixman_image_ref (pixman_image_t *image)
{
image->common.ref_count++;
return image;
}
/* returns TRUE when the image is freed */
PIXMAN_EXPORT pixman_bool_t
pixman_image_unref (pixman_image_t *image)
{
if (_pixman_image_fini (image))
{
free_memory (&image);
return TRUE;
}
return FALSE;
}
PIXMAN_EXPORT void
pixman_image_set_destroy_function (pixman_image_t * image,
pixman_image_destroy_func_t func,
void * data)
{
image->common.destroy_func = func;
image->common.destroy_data = data;
}
PIXMAN_EXPORT void *
pixman_image_get_destroy_data (pixman_image_t *image)
{
return image->common.destroy_data;
}
void
_pixman_image_reset_clip_region (pixman_image_t *image)
{
image->common.have_clip_region = FALSE;
}
/* Executive Summary: This function is a no-op that only exists
* for historical reasons.
*
* There used to be a bug in the X server where it would rely on
* out-of-bounds accesses when it was asked to composite with a
* window as the source. It would create a pixman image pointing
* to some bogus position in memory, but then set a clip region
* to the position where the actual bits were.
*
* Due to a bug in old versions of pixman, where it would not clip
* against the image bounds when a clip region was set, this would
* actually work. So when the pixman bug was fixed, a workaround was
* added to allow certain out-of-bound accesses. This function disabled
* those workarounds.
*
* Since 0.21.2, pixman doesn't do these workarounds anymore, so now
* this function is a no-op.
*/
PIXMAN_EXPORT void
pixman_disable_out_of_bounds_workaround (void)
{
}
static void
compute_image_info (pixman_image_t *image)
{
pixman_format_code_t code;
uint32_t flags = 0;
/* Transform */
if (!image->common.transform)
{
flags |= (FAST_PATH_ID_TRANSFORM |
FAST_PATH_X_UNIT_POSITIVE |
FAST_PATH_Y_UNIT_ZERO |
FAST_PATH_AFFINE_TRANSFORM);
}
else
{
flags |= FAST_PATH_HAS_TRANSFORM;
if (image->common.transform->matrix[2][0] == 0 &&
image->common.transform->matrix[2][1] == 0 &&
image->common.transform->matrix[2][2] == pixman_fixed_1)
{
flags |= FAST_PATH_AFFINE_TRANSFORM;
if (image->common.transform->matrix[0][1] == 0 &&
image->common.transform->matrix[1][0] == 0)
{
if (image->common.transform->matrix[0][0] == -pixman_fixed_1 &&
image->common.transform->matrix[1][1] == -pixman_fixed_1)
{
flags |= FAST_PATH_ROTATE_180_TRANSFORM;
}
flags |= FAST_PATH_SCALE_TRANSFORM;
}
else if (image->common.transform->matrix[0][0] == 0 &&
image->common.transform->matrix[1][1] == 0)
{
pixman_fixed_t m01 = image->common.transform->matrix[0][1];
pixman_fixed_t m10 = image->common.transform->matrix[1][0];
if (m01 == -pixman_fixed_1 && m10 == pixman_fixed_1)
flags |= FAST_PATH_ROTATE_90_TRANSFORM;
else if (m01 == pixman_fixed_1 && m10 == -pixman_fixed_1)
flags |= FAST_PATH_ROTATE_270_TRANSFORM;
}
}
if (image->common.transform->matrix[0][0] > 0)
flags |= FAST_PATH_X_UNIT_POSITIVE;
if (image->common.transform->matrix[1][0] == 0)
flags |= FAST_PATH_Y_UNIT_ZERO;
}
/* Filter */
switch (image->common.filter)
{
case PIXMAN_FILTER_NEAREST:
case PIXMAN_FILTER_FAST:
flags |= (FAST_PATH_NEAREST_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER);
break;
case PIXMAN_FILTER_BILINEAR:
case PIXMAN_FILTER_GOOD:
case PIXMAN_FILTER_BEST:
flags |= (FAST_PATH_BILINEAR_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER);
/* Here we have a chance to optimize BILINEAR filter to NEAREST if
* they are equivalent for the currently used transformation matrix.
*/
if (flags & FAST_PATH_ID_TRANSFORM)
{
flags |= FAST_PATH_NEAREST_FILTER;
}
else if (
/* affine and integer translation components in matrix ... */
((flags & FAST_PATH_AFFINE_TRANSFORM) &&
!pixman_fixed_frac (image->common.transform->matrix[0][2] |
image->common.transform->matrix[1][2])) &&
(
/* ... combined with a simple rotation */
(flags & (FAST_PATH_ROTATE_90_TRANSFORM |
FAST_PATH_ROTATE_180_TRANSFORM |
FAST_PATH_ROTATE_270_TRANSFORM)) ||
/* ... or combined with a simple non-rotated translation */
(image->common.transform->matrix[0][0] == pixman_fixed_1 &&
image->common.transform->matrix[1][1] == pixman_fixed_1 &&
image->common.transform->matrix[0][1] == 0 &&
image->common.transform->matrix[1][0] == 0)
)
)
{
/* FIXME: there are some affine-test failures, showing that
* handling of BILINEAR and NEAREST filter is not quite
* equivalent when getting close to 32K for the translation
* components of the matrix. That's likely some bug, but for
* now just skip BILINEAR->NEAREST optimization in this case.
*/
pixman_fixed_t magic_limit = pixman_int_to_fixed (30000);
if (image->common.transform->matrix[0][2] <= magic_limit &&
image->common.transform->matrix[1][2] <= magic_limit &&
image->common.transform->matrix[0][2] >= -magic_limit &&
image->common.transform->matrix[1][2] >= -magic_limit)
{
flags |= FAST_PATH_NEAREST_FILTER;
}
}
break;
case PIXMAN_FILTER_CONVOLUTION:
break;
case PIXMAN_FILTER_SEPARABLE_CONVOLUTION:
flags |= FAST_PATH_SEPARABLE_CONVOLUTION_FILTER;
break;
default:
flags |= FAST_PATH_NO_CONVOLUTION_FILTER;
break;
}
/* Repeat mode */
switch (image->common.repeat)
{
case PIXMAN_REPEAT_NONE:
flags |=
FAST_PATH_NO_REFLECT_REPEAT |
FAST_PATH_NO_PAD_REPEAT |
FAST_PATH_NO_NORMAL_REPEAT;
break;
case PIXMAN_REPEAT_REFLECT:
flags |=
FAST_PATH_NO_PAD_REPEAT |
FAST_PATH_NO_NONE_REPEAT |
FAST_PATH_NO_NORMAL_REPEAT;
break;
case PIXMAN_REPEAT_PAD:
flags |=
FAST_PATH_NO_REFLECT_REPEAT |
FAST_PATH_NO_NONE_REPEAT |
FAST_PATH_NO_NORMAL_REPEAT;
break;
default:
flags |=
FAST_PATH_NO_REFLECT_REPEAT |
FAST_PATH_NO_PAD_REPEAT |
FAST_PATH_NO_NONE_REPEAT;
break;
}
/* Component alpha */
if (image->common.component_alpha)
flags |= FAST_PATH_COMPONENT_ALPHA;
else
flags |= FAST_PATH_UNIFIED_ALPHA;
flags |= (FAST_PATH_NO_ACCESSORS | FAST_PATH_NARROW_FORMAT);
/* Type specific checks */
switch (image->type)
{
case SOLID:
code = PIXMAN_solid;
if (image->solid.color.alpha == 0xffff)
flags |= FAST_PATH_IS_OPAQUE;
break;
case BITS:
if (image->bits.width == 1 &&
image->bits.height == 1 &&
image->common.repeat != PIXMAN_REPEAT_NONE)
{
code = PIXMAN_solid;
}
else
{
code = image->bits.format;
flags |= FAST_PATH_BITS_IMAGE;
}
if (!PIXMAN_FORMAT_A (image->bits.format) &&
PIXMAN_FORMAT_TYPE (image->bits.format) != PIXMAN_TYPE_GRAY &&
PIXMAN_FORMAT_TYPE (image->bits.format) != PIXMAN_TYPE_COLOR)
{
flags |= FAST_PATH_SAMPLES_OPAQUE;
if (image->common.repeat != PIXMAN_REPEAT_NONE)
flags |= FAST_PATH_IS_OPAQUE;
}
if (image->bits.read_func || image->bits.write_func)
flags &= ~FAST_PATH_NO_ACCESSORS;
if (PIXMAN_FORMAT_IS_WIDE (image->bits.format))
flags &= ~FAST_PATH_NARROW_FORMAT;
if (image->bits.format == PIXMAN_r5g6b5)
flags |= FAST_PATH_16_FORMAT;
break;
case RADIAL:
code = PIXMAN_unknown;
/*
* As explained in pixman-radial-gradient.c, every point of
* the plane has a valid associated radius (and thus will be
* colored) if and only if a is negative (i.e. one of the two
* circles contains the other one).
*/
if (image->radial.a >= 0)
break;
/* Fall through */
case CONICAL:
case LINEAR:
code = PIXMAN_unknown;
if (image->common.repeat != PIXMAN_REPEAT_NONE)
{
int i;
flags |= FAST_PATH_IS_OPAQUE;
for (i = 0; i < image->gradient.n_stops; ++i)
{
if (image->gradient.stops[i].color.alpha != 0xffff)
{
flags &= ~FAST_PATH_IS_OPAQUE;
break;
}
}
}
break;
default:
code = PIXMAN_unknown;
break;
}
/* Alpha map */
if (!image->common.alpha_map)
{
flags |= FAST_PATH_NO_ALPHA_MAP;
}
else
{
if (PIXMAN_FORMAT_IS_WIDE (image->common.alpha_map->format))
flags &= ~FAST_PATH_NARROW_FORMAT;
}
/* Both alpha maps and convolution filters can introduce
* non-opaqueness in otherwise opaque images. Also
* an image with component alpha turned on is only opaque
* if all channels are opaque, so we simply turn it off
* unconditionally for those images.
*/
if (image->common.alpha_map ||
image->common.filter == PIXMAN_FILTER_CONVOLUTION ||
image->common.filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION ||
image->common.component_alpha)
{
flags &= ~(FAST_PATH_IS_OPAQUE | FAST_PATH_SAMPLES_OPAQUE);
}
image->common.flags = flags;
image->common.extended_format_code = code;
}
void
_pixman_image_validate (pixman_image_t *image)
{
if (image->common.dirty)
{
compute_image_info (image);
/* It is important that property_changed is
* called *after* compute_image_info() because
* property_changed() can make use of the flags
* to set up accessors etc.
*/
if (image->common.property_changed)
image->common.property_changed (image);
image->common.dirty = FALSE;
}
if (image->common.alpha_map)
_pixman_image_validate ((pixman_image_t *)image->common.alpha_map);
}
PIXMAN_EXPORT pixman_bool_t
pixman_image_set_clip_region32 (pixman_image_t * image,
pixman_region32_t *region)
{
image_common_t *common = (image_common_t *)image;
pixman_bool_t result;
if (region)
{
if ((result = pixman_region32_copy (&common->clip_region, region)))
image->common.have_clip_region = TRUE;
}
else
{
_pixman_image_reset_clip_region (image);
result = TRUE;
}
image_property_changed (image);
return result;
}
PIXMAN_EXPORT pixman_bool_t
pixman_image_set_clip_region (pixman_image_t * image,
pixman_region16_t *region)
{
image_common_t *common = (image_common_t *)image;
pixman_bool_t result;
if (region)
{
if ((result = pixman_region32_copy_from_region16 (&common->clip_region, region)))
image->common.have_clip_region = TRUE;
}
else
{
_pixman_image_reset_clip_region (image);
result = TRUE;
}
image_property_changed (image);
return result;
}
PIXMAN_EXPORT void
pixman_image_set_has_client_clip (pixman_image_t *image,
pixman_bool_t client_clip)
{
image->common.client_clip = client_clip;
}
PIXMAN_EXPORT pixman_bool_t
pixman_image_set_transform (pixman_image_t * image,
const pixman_transform_t *transform)
{
static const pixman_transform_t id =
{
{ { pixman_fixed_1, 0, 0 },
{ 0, pixman_fixed_1, 0 },
{ 0, 0, pixman_fixed_1 } }
};
image_common_t *common = (image_common_t *)image;
pixman_bool_t result;
if (common->transform == transform)
return TRUE;
if (!transform || memcmp (&id, transform, sizeof (pixman_transform_t)) == 0)
{
free (common->transform);
common->transform = NULL;
result = TRUE;
goto out;
}
if (common->transform &&
memcmp (common->transform, transform, sizeof (pixman_transform_t)) == 0)
{
return TRUE;
}
if (common->transform == NULL)
common->transform = malloc (sizeof (pixman_transform_t));
if (common->transform == NULL)
{
result = FALSE;
goto out;
}
memcpy (common->transform, transform, sizeof(pixman_transform_t));
result = TRUE;
out:
image_property_changed (image);
return result;
}
PIXMAN_EXPORT void
pixman_image_set_repeat (pixman_image_t *image,
pixman_repeat_t repeat)
{
if (image->common.repeat == repeat)
return;
image->common.repeat = repeat;
image_property_changed (image);
}
PIXMAN_EXPORT pixman_bool_t
pixman_image_set_filter (pixman_image_t * image,
pixman_filter_t filter,
const pixman_fixed_t *params,
int n_params)
{
image_common_t *common = (image_common_t *)image;
pixman_fixed_t *new_params;
if (params == common->filter_params && filter == common->filter)
return TRUE;
if (filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION)
{
int width = pixman_fixed_to_int (params[0]);
int height = pixman_fixed_to_int (params[1]);
int x_phase_bits = pixman_fixed_to_int (params[2]);
int y_phase_bits = pixman_fixed_to_int (params[3]);
int n_x_phases = (1 << x_phase_bits);
int n_y_phases = (1 << y_phase_bits);
return_val_if_fail (
n_params == 4 + n_x_phases * width + n_y_phases * height, FALSE);
}
new_params = NULL;
if (params)
{
new_params = pixman_malloc_ab (n_params, sizeof (pixman_fixed_t));
if (!new_params)
return FALSE;
memcpy (new_params,
params, n_params * sizeof (pixman_fixed_t));
}
common->filter = filter;
if (common->filter_params)
free (common->filter_params);
common->filter_params = new_params;
common->n_filter_params = n_params;
image_property_changed (image);
return TRUE;
}
PIXMAN_EXPORT void
pixman_image_set_source_clipping (pixman_image_t *image,
pixman_bool_t clip_sources)
{
if (image->common.clip_sources == clip_sources)
return;
image->common.clip_sources = clip_sources;
image_property_changed (image);
}
/* Unlike all the other property setters, this function does not
* copy the content of indexed. Doing this copying is simply
* way, way too expensive.
*/
PIXMAN_EXPORT void
pixman_image_set_indexed (pixman_image_t * image,
const pixman_indexed_t *indexed)
{
bits_image_t *bits = (bits_image_t *)image;
if (bits->indexed == indexed)
return;
bits->indexed = indexed;
image_property_changed (image);
}
PIXMAN_EXPORT void
pixman_image_set_alpha_map (pixman_image_t *image,
pixman_image_t *alpha_map,
int16_t x,
int16_t y)
{
image_common_t *common = (image_common_t *)image;
return_if_fail (!alpha_map || alpha_map->type == BITS);
if (alpha_map && common->alpha_count > 0)
{
/* If this image is being used as an alpha map itself,
* then you can't give it an alpha map of its own.
*/
return;
}
if (alpha_map && alpha_map->common.alpha_map)
{
/* If the image has an alpha map of its own,
* then it can't be used as an alpha map itself
*/
return;
}
if (common->alpha_map != (bits_image_t *)alpha_map)
{
if (common->alpha_map)
{
common->alpha_map->common.alpha_count--;
pixman_image_unref ((pixman_image_t *)common->alpha_map);
}
if (alpha_map)
{
common->alpha_map = (bits_image_t *)pixman_image_ref (alpha_map);
common->alpha_map->common.alpha_count++;
}
else
{
common->alpha_map = NULL;
}
}
common->alpha_origin_x = x;
common->alpha_origin_y = y;
image_property_changed (image);
}
PIXMAN_EXPORT void
pixman_image_set_component_alpha (pixman_image_t *image,
pixman_bool_t component_alpha)
{
if (image->common.component_alpha == component_alpha)
return;
image->common.component_alpha = component_alpha;
image_property_changed (image);
}
PIXMAN_EXPORT pixman_bool_t
pixman_image_get_component_alpha (pixman_image_t *image)
{
return image->common.component_alpha;
}
PIXMAN_EXPORT void
pixman_image_set_accessors (pixman_image_t * image,
pixman_read_memory_func_t read_func,
pixman_write_memory_func_t write_func)
{
return_if_fail (image != NULL);
if (image->type == BITS)
{
image->bits.read_func = read_func;
image->bits.write_func = write_func;
image_property_changed (image);
}
}
PIXMAN_EXPORT uint32_t *
pixman_image_get_data (pixman_image_t *image)
{
if (image->type == BITS)
return image->bits.bits;
return NULL;
}
PIXMAN_EXPORT int
pixman_image_get_width (pixman_image_t *image)
{
if (image->type == BITS)
return image->bits.width;
return 0;
}
PIXMAN_EXPORT int
pixman_image_get_height (pixman_image_t *image)
{
if (image->type == BITS)
return image->bits.height;
return 0;
}
PIXMAN_EXPORT int
pixman_image_get_stride (pixman_image_t *image)
{
if (image->type == BITS)
return image->bits.rowstride * (int) sizeof (uint32_t);
return 0;
}
PIXMAN_EXPORT int
pixman_image_get_depth (pixman_image_t *image)
{
if (image->type == BITS)
return PIXMAN_FORMAT_DEPTH (image->bits.format);
return 0;
}
PIXMAN_EXPORT pixman_format_code_t
pixman_image_get_format (pixman_image_t *image)
{
if (image->type == BITS)
return image->bits.format;
return PIXMAN_null;
}
uint32_t
_pixman_image_get_solid (pixman_implementation_t *imp,
pixman_image_t * image,
pixman_format_code_t format)
{
uint32_t result;
if (image->type == SOLID)
{
result = image->solid.color_32;
}
else if (image->type == BITS)
{
if (image->bits.format == PIXMAN_a8r8g8b8)
result = image->bits.bits[0];
else if (image->bits.format == PIXMAN_x8r8g8b8)
result = image->bits.bits[0] | 0xff000000;
else if (image->bits.format == PIXMAN_a8)
result = (*(uint8_t *)image->bits.bits) << 24;
else
goto otherwise;
}
else
{
pixman_iter_t iter;
otherwise:
_pixman_implementation_src_iter_init (
imp, &iter, image, 0, 0, 1, 1,
(uint8_t *)&result,
ITER_NARROW, image->common.flags);
result = *iter.get_scanline (&iter, NULL);
}
/* If necessary, convert RGB <--> BGR. */
if (PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB
&& PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB_SRGB)
{
result = (((result & 0xff000000) >> 0) |
((result & 0x00ff0000) >> 16) |
((result & 0x0000ff00) >> 0) |
((result & 0x000000ff) << 16));
}
return result;
}

View file

@ -0,0 +1,405 @@
/*
* Copyright © 2009 Red Hat, Inc.
*
* 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 "pixman-private.h"
pixman_implementation_t *
_pixman_implementation_create (pixman_implementation_t *fallback,
const pixman_fast_path_t *fast_paths)
{
pixman_implementation_t *imp;
assert (fast_paths);
if ((imp = malloc (sizeof (pixman_implementation_t))))
{
pixman_implementation_t *d;
memset (imp, 0, sizeof *imp);
imp->fallback = fallback;
imp->fast_paths = fast_paths;
/* Make sure the whole fallback chain has the right toplevel */
for (d = imp; d != NULL; d = d->fallback)
d->toplevel = imp;
}
return imp;
}
#define N_CACHED_FAST_PATHS 8
typedef struct
{
struct
{
pixman_implementation_t * imp;
pixman_fast_path_t fast_path;
} cache [N_CACHED_FAST_PATHS];
} cache_t;
PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache);
static void
dummy_composite_rect (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
}
void
_pixman_implementation_lookup_composite (pixman_implementation_t *toplevel,
pixman_op_t op,
pixman_format_code_t src_format,
uint32_t src_flags,
pixman_format_code_t mask_format,
uint32_t mask_flags,
pixman_format_code_t dest_format,
uint32_t dest_flags,
pixman_implementation_t **out_imp,
pixman_composite_func_t *out_func)
{
pixman_implementation_t *imp;
cache_t *cache;
int i;
/* Check cache for fast paths */
cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache);
/* Bug 1324130 - For compatibility with Windows XP, we have to use Tls
* functions for the per-thread fast-path cache instead of the safer
* __declspec(thread) mechanism. If the Tls functions fail to set up
* the storage for some reason, cache will end up null here. As a
* temporary workaround, just check that cache is not null before
* using it. The implementation lookup will still function without the
* fast-path cache, however, it will incur a slow linear search.
*/
if (cache) for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
{
const pixman_fast_path_t *info = &(cache->cache[i].fast_path);
/* Note that we check for equality here, not whether
* the cached fast path matches. This is to prevent
* us from selecting an overly general fast path
* when a more specific one would work.
*/
if (info->op == op &&
info->src_format == src_format &&
info->mask_format == mask_format &&
info->dest_format == dest_format &&
info->src_flags == src_flags &&
info->mask_flags == mask_flags &&
info->dest_flags == dest_flags &&
info->func)
{
*out_imp = cache->cache[i].imp;
*out_func = cache->cache[i].fast_path.func;
goto update_cache;
}
}
for (imp = toplevel; imp != NULL; imp = imp->fallback)
{
const pixman_fast_path_t *info = imp->fast_paths;
while (info->op != PIXMAN_OP_NONE)
{
if ((info->op == op || info->op == PIXMAN_OP_any) &&
/* Formats */
((info->src_format == src_format) ||
(info->src_format == PIXMAN_any)) &&
((info->mask_format == mask_format) ||
(info->mask_format == PIXMAN_any)) &&
((info->dest_format == dest_format) ||
(info->dest_format == PIXMAN_any)) &&
/* Flags */
(info->src_flags & src_flags) == info->src_flags &&
(info->mask_flags & mask_flags) == info->mask_flags &&
(info->dest_flags & dest_flags) == info->dest_flags)
{
*out_imp = imp;
*out_func = info->func;
/* Set i to the last spot in the cache so that the
* move-to-front code below will work
*/
i = N_CACHED_FAST_PATHS - 1;
goto update_cache;
}
++info;
}
}
/* We should never reach this point */
_pixman_log_error (FUNC, "No known composite function\n");
*out_imp = NULL;
*out_func = dummy_composite_rect;
update_cache:
if (cache && i)
{
while (i--)
cache->cache[i + 1] = cache->cache[i];
cache->cache[0].imp = *out_imp;
cache->cache[0].fast_path.op = op;
cache->cache[0].fast_path.src_format = src_format;
cache->cache[0].fast_path.src_flags = src_flags;
cache->cache[0].fast_path.mask_format = mask_format;
cache->cache[0].fast_path.mask_flags = mask_flags;
cache->cache[0].fast_path.dest_format = dest_format;
cache->cache[0].fast_path.dest_flags = dest_flags;
cache->cache[0].fast_path.func = *out_func;
}
}
static void
dummy_combine (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * pd,
const uint32_t * ps,
const uint32_t * pm,
int w)
{
}
pixman_combine_32_func_t
_pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
pixman_op_t op,
pixman_bool_t component_alpha,
pixman_bool_t narrow,
pixman_bool_t rgb16)
{
while (imp)
{
pixman_combine_32_func_t f = NULL;
switch ((narrow << 1) | component_alpha)
{
case 0: /* not narrow, not component alpha */
f = (pixman_combine_32_func_t)imp->combine_float[op];
break;
case 1: /* not narrow, component_alpha */
f = (pixman_combine_32_func_t)imp->combine_float_ca[op];
break;
case 2: /* narrow, not component alpha */
f = imp->combine_32[op];
break;
case 3: /* narrow, component_alpha */
f = imp->combine_32_ca[op];
break;
}
if (rgb16)
f = (pixman_combine_32_func_t *)imp->combine_16[op];
if (f)
return f;
imp = imp->fallback;
}
/* We should never reach this point */
_pixman_log_error (FUNC, "No known combine function\n");
return dummy_combine;
}
pixman_bool_t
_pixman_implementation_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 dest_x,
int dest_y,
int width,
int height)
{
while (imp)
{
if (imp->blt &&
(*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride,
src_bpp, dst_bpp, src_x, src_y, dest_x, dest_y,
width, height))
{
return TRUE;
}
imp = imp->fallback;
}
return FALSE;
}
pixman_bool_t
_pixman_implementation_fill (pixman_implementation_t *imp,
uint32_t * bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t filler)
{
while (imp)
{
if (imp->fill &&
((*imp->fill) (imp, bits, stride, bpp, x, y, width, height, filler)))
{
return TRUE;
}
imp = imp->fallback;
}
return FALSE;
}
pixman_bool_t
_pixman_implementation_src_iter_init (pixman_implementation_t *imp,
pixman_iter_t *iter,
pixman_image_t *image,
int x,
int y,
int width,
int height,
uint8_t *buffer,
iter_flags_t iter_flags,
uint32_t image_flags)
{
iter->image = image;
iter->buffer = (uint32_t *)buffer;
iter->x = x;
iter->y = y;
iter->width = width;
iter->height = height;
iter->iter_flags = iter_flags;
iter->image_flags = image_flags;
while (imp)
{
if (imp->src_iter_init && (*imp->src_iter_init) (imp, iter))
return TRUE;
imp = imp->fallback;
}
return FALSE;
}
pixman_bool_t
_pixman_implementation_dest_iter_init (pixman_implementation_t *imp,
pixman_iter_t *iter,
pixman_image_t *image,
int x,
int y,
int width,
int height,
uint8_t *buffer,
iter_flags_t iter_flags,
uint32_t image_flags)
{
iter->image = image;
iter->buffer = (uint32_t *)buffer;
iter->x = x;
iter->y = y;
iter->width = width;
iter->height = height;
iter->iter_flags = iter_flags;
iter->image_flags = image_flags;
while (imp)
{
if (imp->dest_iter_init && (*imp->dest_iter_init) (imp, iter))
return TRUE;
imp = imp->fallback;
}
return FALSE;
}
pixman_bool_t
_pixman_disabled (const char *name)
{
const char *env;
if ((env = getenv ("PIXMAN_DISABLE")))
{
do
{
const char *end;
int len;
if ((end = strchr (env, ' ')))
len = end - env;
else
len = strlen (env);
if (strlen (name) == len && strncmp (name, env, len) == 0)
{
printf ("pixman: Disabled %s implementation\n", name);
return TRUE;
}
env += len;
}
while (*env++);
}
return FALSE;
}
pixman_implementation_t *
_pixman_choose_implementation (void)
{
pixman_implementation_t *imp;
imp = _pixman_implementation_create_general();
if (!_pixman_disabled ("fast"))
imp = _pixman_implementation_create_fast_path (imp);
imp = _pixman_x86_get_implementations (imp);
imp = _pixman_arm_get_implementations (imp);
imp = _pixman_ppc_get_implementations (imp);
imp = _pixman_mips_get_implementations (imp);
imp = _pixman_implementation_create_noop (imp);
return imp;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,444 @@
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
/*
* 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
*
* 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 Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard 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 "pixman-private.h"
#include "pixman-dither.h"
static pixman_bool_t
linear_gradient_is_horizontal (pixman_image_t *image,
int x,
int y,
int width,
int height)
{
linear_gradient_t *linear = (linear_gradient_t *)image;
pixman_vector_t v;
pixman_fixed_32_32_t l;
pixman_fixed_48_16_t dx, dy;
double inc;
if (image->common.transform)
{
/* projective transformation */
if (image->common.transform->matrix[2][0] != 0 ||
image->common.transform->matrix[2][1] != 0 ||
image->common.transform->matrix[2][2] == 0)
{
return FALSE;
}
v.vector[0] = image->common.transform->matrix[0][1];
v.vector[1] = image->common.transform->matrix[1][1];
v.vector[2] = image->common.transform->matrix[2][2];
}
else
{
v.vector[0] = 0;
v.vector[1] = pixman_fixed_1;
v.vector[2] = pixman_fixed_1;
}
dx = linear->p2.x - linear->p1.x;
dy = linear->p2.y - linear->p1.y;
l = dx * dx + dy * dy;
if (l == 0)
return FALSE;
/*
* compute how much the input of the gradient walked changes
* when moving vertically through the whole image
*/
inc = height * (double) pixman_fixed_1 * pixman_fixed_1 *
(dx * v.vector[0] + dy * v.vector[1]) /
(v.vector[2] * (double) l);
/* check that casting to integer would result in 0 */
if (-1 < inc && inc < 1)
return TRUE;
return FALSE;
}
static uint32_t *
linear_get_scanline_narrow (pixman_iter_t *iter,
const uint32_t *mask)
{
pixman_image_t *image = iter->image;
int x = iter->x;
int y = iter->y;
int width = iter->width;
uint32_t * buffer = iter->buffer;
pixman_vector_t v, unit;
pixman_fixed_32_32_t l;
pixman_fixed_48_16_t dx, dy;
gradient_t *gradient = (gradient_t *)image;
linear_gradient_t *linear = (linear_gradient_t *)image;
uint32_t *end = buffer + width;
pixman_gradient_walker_t walker;
_pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
if (image->common.transform)
{
if (!pixman_transform_point_3d (image->common.transform, &v))
return iter->buffer;
unit.vector[0] = image->common.transform->matrix[0][0];
unit.vector[1] = image->common.transform->matrix[1][0];
unit.vector[2] = image->common.transform->matrix[2][0];
}
else
{
unit.vector[0] = pixman_fixed_1;
unit.vector[1] = 0;
unit.vector[2] = 0;
}
dx = linear->p2.x - linear->p1.x;
dy = linear->p2.y - linear->p1.y;
l = dx * dx + dy * dy;
if (l == 0 || unit.vector[2] == 0)
{
/* affine transformation only */
pixman_fixed_32_32_t t, next_inc;
double inc;
if (l == 0 || v.vector[2] == 0)
{
t = 0;
inc = 0;
}
else
{
double invden, v2;
invden = pixman_fixed_1 * (double) pixman_fixed_1 /
(l * (double) v.vector[2]);
v2 = v.vector[2] * (1. / pixman_fixed_1);
t = ((dx * v.vector[0] + dy * v.vector[1]) -
(dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
}
next_inc = 0;
if (((pixman_fixed_32_32_t )(inc * width)) == 0)
{
register uint32_t color;
color = _pixman_gradient_walker_pixel (&walker, t);
while (buffer < end)
*buffer++ = color;
}
else
{
int i;
i = 0;
while (buffer < end)
{
if (!mask || *mask++)
{
*buffer = _pixman_gradient_walker_pixel (&walker,
t + next_inc);
}
i++;
next_inc = inc * i;
buffer++;
}
}
}
else
{
/* projective transformation */
double t;
t = 0;
while (buffer < end)
{
if (!mask || *mask++)
{
if (v.vector[2] != 0)
{
double invden, v2;
invden = pixman_fixed_1 * (double) pixman_fixed_1 /
(l * (double) v.vector[2]);
v2 = v.vector[2] * (1. / pixman_fixed_1);
t = ((dx * v.vector[0] + dy * v.vector[1]) -
(dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
}
*buffer = _pixman_gradient_walker_pixel (&walker, t);
}
++buffer;
v.vector[0] += unit.vector[0];
v.vector[1] += unit.vector[1];
v.vector[2] += unit.vector[2];
}
}
iter->y++;
return iter->buffer;
}
static uint32_t *
linear_get_scanline_16 (pixman_iter_t *iter,
const uint32_t *mask)
{
pixman_image_t *image = iter->image;
int x = iter->x;
int y = iter->y;
int width = iter->width;
uint16_t * buffer = (uint16_t*)iter->buffer;
pixman_bool_t toggle = ((x ^ y) & 1);
pixman_vector_t v, unit;
pixman_fixed_32_32_t l;
pixman_fixed_48_16_t dx, dy;
gradient_t *gradient = (gradient_t *)image;
linear_gradient_t *linear = (linear_gradient_t *)image;
uint16_t *end = buffer + width;
pixman_gradient_walker_t walker;
_pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
if (image->common.transform)
{
if (!pixman_transform_point_3d (image->common.transform, &v))
return iter->buffer;
unit.vector[0] = image->common.transform->matrix[0][0];
unit.vector[1] = image->common.transform->matrix[1][0];
unit.vector[2] = image->common.transform->matrix[2][0];
}
else
{
unit.vector[0] = pixman_fixed_1;
unit.vector[1] = 0;
unit.vector[2] = 0;
}
dx = linear->p2.x - linear->p1.x;
dy = linear->p2.y - linear->p1.y;
l = dx * dx + dy * dy;
if (l == 0 || unit.vector[2] == 0)
{
/* affine transformation only */
pixman_fixed_32_32_t t, next_inc;
double inc;
if (l == 0 || v.vector[2] == 0)
{
t = 0;
inc = 0;
}
else
{
double invden, v2;
invden = pixman_fixed_1 * (double) pixman_fixed_1 /
(l * (double) v.vector[2]);
v2 = v.vector[2] * (1. / pixman_fixed_1);
t = ((dx * v.vector[0] + dy * v.vector[1]) -
(dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
}
next_inc = 0;
if (((pixman_fixed_32_32_t )(inc * width)) == 0)
{
register uint32_t color;
uint16_t dither_diff;
uint16_t color16;
uint16_t color16b;
color = _pixman_gradient_walker_pixel (&walker, t);
color16 = dither_8888_to_0565(color, toggle);
color16b = dither_8888_to_0565(color, toggle^1);
// compute the difference
dither_diff = color16 ^ color16b;
while (buffer < end) {
*buffer++ = color16;
// use dither_diff to toggle between color16 and color16b
color16 ^= dither_diff;
toggle ^= 1;
}
}
else
{
int i;
i = 0;
while (buffer < end)
{
if (!mask || *mask++)
{
*buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker,
t + next_inc),
toggle);
}
toggle ^= 1;
i++;
next_inc = inc * i;
buffer++;
}
}
}
else
{
/* projective transformation */
double t;
t = 0;
while (buffer < end)
{
if (!mask || *mask++)
{
if (v.vector[2] != 0)
{
double invden, v2;
invden = pixman_fixed_1 * (double) pixman_fixed_1 /
(l * (double) v.vector[2]);
v2 = v.vector[2] * (1. / pixman_fixed_1);
t = ((dx * v.vector[0] + dy * v.vector[1]) -
(dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
}
*buffer = dither_8888_to_0565(_pixman_gradient_walker_pixel (&walker, t),
toggle);
}
toggle ^= 1;
++buffer;
v.vector[0] += unit.vector[0];
v.vector[1] += unit.vector[1];
v.vector[2] += unit.vector[2];
}
}
iter->y++;
return iter->buffer;
}
static uint32_t *
linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
{
uint32_t *buffer = linear_get_scanline_narrow (iter, NULL);
pixman_expand_to_float (
(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
return buffer;
}
void
_pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
{
// XXX: we can't use this optimization when dithering
if (0 && linear_gradient_is_horizontal (
iter->image, iter->x, iter->y, iter->width, iter->height))
{
if (iter->iter_flags & ITER_16)
linear_get_scanline_16 (iter, NULL);
else if (iter->iter_flags & ITER_NARROW)
linear_get_scanline_narrow (iter, NULL);
else
linear_get_scanline_wide (iter, NULL);
iter->get_scanline = _pixman_iter_get_scanline_noop;
}
else
{
if (iter->iter_flags & ITER_16)
iter->get_scanline = linear_get_scanline_16;
else if (iter->iter_flags & ITER_NARROW)
iter->get_scanline = linear_get_scanline_narrow;
else
iter->get_scanline = linear_get_scanline_wide;
}
}
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_linear_gradient (const pixman_point_fixed_t * p1,
const pixman_point_fixed_t * p2,
const pixman_gradient_stop_t *stops,
int n_stops)
{
pixman_image_t *image;
linear_gradient_t *linear;
image = _pixman_image_allocate ();
if (!image)
return NULL;
linear = &image->linear;
if (!_pixman_init_gradient (&linear->common, stops, n_stops))
{
free (image);
return NULL;
}
linear->p1 = *p1;
linear->p2 = *p2;
image->type = LINEAR;
return image;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,681 @@
/*
* Copyright (c) 2012
* MIPS Technologies, Inc., California.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Author: Nemanja Lukic (nlukic@mips.com)
*/
#ifndef PIXMAN_MIPS_DSPR2_ASM_H
#define PIXMAN_MIPS_DSPR2_ASM_H
#define zero $0
#define AT $1
#define v0 $2
#define v1 $3
#define a0 $4
#define a1 $5
#define a2 $6
#define a3 $7
#define t0 $8
#define t1 $9
#define t2 $10
#define t3 $11
#define t4 $12
#define t5 $13
#define t6 $14
#define t7 $15
#define s0 $16
#define s1 $17
#define s2 $18
#define s3 $19
#define s4 $20
#define s5 $21
#define s6 $22
#define s7 $23
#define t8 $24
#define t9 $25
#define k0 $26
#define k1 $27
#define gp $28
#define sp $29
#define fp $30
#define s8 $30
#define ra $31
/*
* LEAF_MIPS32R2 - declare leaf routine for MIPS32r2
*/
#define LEAF_MIPS32R2(symbol) \
.globl symbol; \
.align 2; \
.type symbol, @function; \
.ent symbol, 0; \
symbol: .frame sp, 0, ra; \
.set push; \
.set arch=mips32r2; \
.set noreorder; \
.set noat;
/*
* LEAF_MIPS32R2 - declare leaf routine for MIPS DSPr2
*/
#define LEAF_MIPS_DSPR2(symbol) \
LEAF_MIPS32R2(symbol) \
.set dspr2;
/*
* END - mark end of function
*/
#define END(function) \
.set pop; \
.end function; \
.size function,.-function
/*
* Checks if stack offset is big enough for storing/restoring regs_num
* number of register to/from stack. Stack offset must be greater than
* or equal to the number of bytes needed for storing registers (regs_num*4).
* Since MIPS ABI allows usage of first 16 bytes of stack frame (this is
* preserved for input arguments of the functions, already stored in a0-a3),
* stack size can be further optimized by utilizing this space.
*/
.macro CHECK_STACK_OFFSET regs_num, stack_offset
.if \stack_offset < \regs_num * 4 - 16
.error "Stack offset too small."
.endif
.endm
/*
* Saves set of registers on stack. Maximum number of registers that
* can be saved on stack is limitted to 14 (a0-a3, v0-v1 and s0-s7).
* Stack offset is number of bytes that are added to stack pointer (sp)
* before registers are pushed in order to provide enough space on stack
* (offset must be multiple of 4, and must be big enough, as described by
* CHECK_STACK_OFFSET macro). This macro is intended to be used in
* combination with RESTORE_REGS_FROM_STACK macro. Example:
* SAVE_REGS_ON_STACK 4, v0, v1, s0, s1
* RESTORE_REGS_FROM_STACK 4, v0, v1, s0, s1
*/
.macro SAVE_REGS_ON_STACK stack_offset = 0, r1, \
r2 = 0, r3 = 0, r4 = 0, \
r5 = 0, r6 = 0, r7 = 0, \
r8 = 0, r9 = 0, r10 = 0, \
r11 = 0, r12 = 0, r13 = 0, \
r14 = 0
.if (\stack_offset < 0) || (\stack_offset - (\stack_offset / 4) * 4)
.error "Stack offset must be pozitive and multiple of 4."
.endif
.if \stack_offset != 0
addiu sp, sp, -\stack_offset
.endif
sw \r1, 0(sp)
.if \r2 != 0
sw \r2, 4(sp)
.endif
.if \r3 != 0
sw \r3, 8(sp)
.endif
.if \r4 != 0
sw \r4, 12(sp)
.endif
.if \r5 != 0
CHECK_STACK_OFFSET 5, \stack_offset
sw \r5, 16(sp)
.endif
.if \r6 != 0
CHECK_STACK_OFFSET 6, \stack_offset
sw \r6, 20(sp)
.endif
.if \r7 != 0
CHECK_STACK_OFFSET 7, \stack_offset
sw \r7, 24(sp)
.endif
.if \r8 != 0
CHECK_STACK_OFFSET 8, \stack_offset
sw \r8, 28(sp)
.endif
.if \r9 != 0
CHECK_STACK_OFFSET 9, \stack_offset
sw \r9, 32(sp)
.endif
.if \r10 != 0
CHECK_STACK_OFFSET 10, \stack_offset
sw \r10, 36(sp)
.endif
.if \r11 != 0
CHECK_STACK_OFFSET 11, \stack_offset
sw \r11, 40(sp)
.endif
.if \r12 != 0
CHECK_STACK_OFFSET 12, \stack_offset
sw \r12, 44(sp)
.endif
.if \r13 != 0
CHECK_STACK_OFFSET 13, \stack_offset
sw \r13, 48(sp)
.endif
.if \r14 != 0
CHECK_STACK_OFFSET 14, \stack_offset
sw \r14, 52(sp)
.endif
.endm
/*
* Restores set of registers from stack. Maximum number of registers that
* can be restored from stack is limitted to 14 (a0-a3, v0-v1 and s0-s7).
* Stack offset is number of bytes that are added to stack pointer (sp)
* after registers are restored (offset must be multiple of 4, and must
* be big enough, as described by CHECK_STACK_OFFSET macro). This macro is
* intended to be used in combination with RESTORE_REGS_FROM_STACK macro.
* Example:
* SAVE_REGS_ON_STACK 4, v0, v1, s0, s1
* RESTORE_REGS_FROM_STACK 4, v0, v1, s0, s1
*/
.macro RESTORE_REGS_FROM_STACK stack_offset = 0, r1, \
r2 = 0, r3 = 0, r4 = 0, \
r5 = 0, r6 = 0, r7 = 0, \
r8 = 0, r9 = 0, r10 = 0, \
r11 = 0, r12 = 0, r13 = 0, \
r14 = 0
.if (\stack_offset < 0) || (\stack_offset - (\stack_offset/4)*4)
.error "Stack offset must be pozitive and multiple of 4."
.endif
lw \r1, 0(sp)
.if \r2 != 0
lw \r2, 4(sp)
.endif
.if \r3 != 0
lw \r3, 8(sp)
.endif
.if \r4 != 0
lw \r4, 12(sp)
.endif
.if \r5 != 0
CHECK_STACK_OFFSET 5, \stack_offset
lw \r5, 16(sp)
.endif
.if \r6 != 0
CHECK_STACK_OFFSET 6, \stack_offset
lw \r6, 20(sp)
.endif
.if \r7 != 0
CHECK_STACK_OFFSET 7, \stack_offset
lw \r7, 24(sp)
.endif
.if \r8 != 0
CHECK_STACK_OFFSET 8, \stack_offset
lw \r8, 28(sp)
.endif
.if \r9 != 0
CHECK_STACK_OFFSET 9, \stack_offset
lw \r9, 32(sp)
.endif
.if \r10 != 0
CHECK_STACK_OFFSET 10, \stack_offset
lw \r10, 36(sp)
.endif
.if \r11 != 0
CHECK_STACK_OFFSET 11, \stack_offset
lw \r11, 40(sp)
.endif
.if \r12 != 0
CHECK_STACK_OFFSET 12, \stack_offset
lw \r12, 44(sp)
.endif
.if \r13 != 0
CHECK_STACK_OFFSET 13, \stack_offset
lw \r13, 48(sp)
.endif
.if \r14 != 0
CHECK_STACK_OFFSET 14, \stack_offset
lw \r14, 52(sp)
.endif
.if \stack_offset != 0
addiu sp, sp, \stack_offset
.endif
.endm
/*
* Conversion of single r5g6b5 pixel (in_565) to single a8r8g8b8 pixel
* returned in (out_8888) register. Requires two temporary registers
* (scratch1 and scratch2).
*/
.macro CONVERT_1x0565_TO_1x8888 in_565, \
out_8888, \
scratch1, scratch2
lui \out_8888, 0xff00
sll \scratch1, \in_565, 0x3
andi \scratch2, \scratch1, 0xff
ext \scratch1, \in_565, 0x2, 0x3
or \scratch1, \scratch2, \scratch1
or \out_8888, \out_8888, \scratch1
sll \scratch1, \in_565, 0x5
andi \scratch1, \scratch1, 0xfc00
srl \scratch2, \in_565, 0x1
andi \scratch2, \scratch2, 0x300
or \scratch2, \scratch1, \scratch2
or \out_8888, \out_8888, \scratch2
andi \scratch1, \in_565, 0xf800
srl \scratch2, \scratch1, 0x5
andi \scratch2, \scratch2, 0xff00
or \scratch1, \scratch1, \scratch2
sll \scratch1, \scratch1, 0x8
or \out_8888, \out_8888, \scratch1
.endm
/*
* Conversion of two r5g6b5 pixels (in1_565 and in2_565) to two a8r8g8b8 pixels
* returned in (out1_8888 and out2_8888) registers. Requires four scratch
* registers (scratch1 ... scratch4). It also requires maskG and maskB for
* color component extractions. These masks must have following values:
* li maskG, 0x07e007e0
* li maskB, 0x001F001F
*/
.macro CONVERT_2x0565_TO_2x8888 in1_565, in2_565, \
out1_8888, out2_8888, \
maskG, maskB, \
scratch1, scratch2, scratch3, scratch4
sll \scratch1, \in1_565, 16
or \scratch1, \scratch1, \in2_565
lui \out2_8888, 0xff00
ori \out2_8888, \out2_8888, 0xff00
shrl.ph \scratch2, \scratch1, 11
and \scratch3, \scratch1, \maskG
shra.ph \scratch4, \scratch2, 2
shll.ph \scratch2, \scratch2, 3
shll.ph \scratch3, \scratch3, 5
or \scratch2, \scratch2, \scratch4
shrl.qb \scratch4, \scratch3, 6
or \out2_8888, \out2_8888, \scratch2
or \scratch3, \scratch3, \scratch4
and \scratch1, \scratch1, \maskB
shll.ph \scratch2, \scratch1, 3
shra.ph \scratch4, \scratch1, 2
or \scratch2, \scratch2, \scratch4
or \scratch3, \scratch2, \scratch3
precrq.ph.w \out1_8888, \out2_8888, \scratch3
precr_sra.ph.w \out2_8888, \scratch3, 0
.endm
/*
* Conversion of single a8r8g8b8 pixel (in_8888) to single r5g6b5 pixel
* returned in (out_565) register. Requires two temporary registers
* (scratch1 and scratch2).
*/
.macro CONVERT_1x8888_TO_1x0565 in_8888, \
out_565, \
scratch1, scratch2
ext \out_565, \in_8888, 0x3, 0x5
srl \scratch1, \in_8888, 0x5
andi \scratch1, \scratch1, 0x07e0
srl \scratch2, \in_8888, 0x8
andi \scratch2, \scratch2, 0xf800
or \out_565, \out_565, \scratch1
or \out_565, \out_565, \scratch2
.endm
/*
* Conversion of two a8r8g8b8 pixels (in1_8888 and in2_8888) to two r5g6b5
* pixels returned in (out1_565 and out2_565) registers. Requires two temporary
* registers (scratch1 and scratch2). It also requires maskR, maskG and maskB
* for color component extractions. These masks must have following values:
* li maskR, 0xf800f800
* li maskG, 0x07e007e0
* li maskB, 0x001F001F
* Value of input register in2_8888 is lost.
*/
.macro CONVERT_2x8888_TO_2x0565 in1_8888, in2_8888, \
out1_565, out2_565, \
maskR, maskG, maskB, \
scratch1, scratch2
precrq.ph.w \scratch1, \in2_8888, \in1_8888
precr_sra.ph.w \in2_8888, \in1_8888, 0
shll.ph \scratch1, \scratch1, 8
srl \in2_8888, \in2_8888, 3
and \scratch2, \in2_8888, \maskB
and \scratch1, \scratch1, \maskR
srl \in2_8888, \in2_8888, 2
and \out2_565, \in2_8888, \maskG
or \out2_565, \out2_565, \scratch2
or \out1_565, \out2_565, \scratch1
srl \out2_565, \out1_565, 16
.endm
/*
* Multiply pixel (a8) with single pixel (a8r8g8b8). It requires maskLSR needed
* for rounding process. maskLSR must have following value:
* li maskLSR, 0x00ff00ff
*/
.macro MIPS_UN8x4_MUL_UN8 s_8888, \
m_8, \
d_8888, \
maskLSR, \
scratch1, scratch2, scratch3
replv.ph \m_8, \m_8 /* 0 | M | 0 | M */
muleu_s.ph.qbl \scratch1, \s_8888, \m_8 /* A*M | R*M */
muleu_s.ph.qbr \scratch2, \s_8888, \m_8 /* G*M | B*M */
shra_r.ph \scratch3, \scratch1, 8
shra_r.ph \d_8888, \scratch2, 8
and \scratch3, \scratch3, \maskLSR /* 0 |A*M| 0 |R*M */
and \d_8888, \d_8888, \maskLSR /* 0 |G*M| 0 |B*M */
addq.ph \scratch1, \scratch1, \scratch3 /* A*M+A*M | R*M+R*M */
addq.ph \scratch2, \scratch2, \d_8888 /* G*M+G*M | B*M+B*M */
shra_r.ph \scratch1, \scratch1, 8
shra_r.ph \scratch2, \scratch2, 8
precr.qb.ph \d_8888, \scratch1, \scratch2
.endm
/*
* Multiply two pixels (a8) with two pixels (a8r8g8b8). It requires maskLSR
* needed for rounding process. maskLSR must have following value:
* li maskLSR, 0x00ff00ff
*/
.macro MIPS_2xUN8x4_MUL_2xUN8 s1_8888, \
s2_8888, \
m1_8, \
m2_8, \
d1_8888, \
d2_8888, \
maskLSR, \
scratch1, scratch2, scratch3, \
scratch4, scratch5, scratch6
replv.ph \m1_8, \m1_8 /* 0 | M1 | 0 | M1 */
replv.ph \m2_8, \m2_8 /* 0 | M2 | 0 | M2 */
muleu_s.ph.qbl \scratch1, \s1_8888, \m1_8 /* A1*M1 | R1*M1 */
muleu_s.ph.qbr \scratch2, \s1_8888, \m1_8 /* G1*M1 | B1*M1 */
muleu_s.ph.qbl \scratch3, \s2_8888, \m2_8 /* A2*M2 | R2*M2 */
muleu_s.ph.qbr \scratch4, \s2_8888, \m2_8 /* G2*M2 | B2*M2 */
shra_r.ph \scratch5, \scratch1, 8
shra_r.ph \d1_8888, \scratch2, 8
shra_r.ph \scratch6, \scratch3, 8
shra_r.ph \d2_8888, \scratch4, 8
and \scratch5, \scratch5, \maskLSR /* 0 |A1*M1| 0 |R1*M1 */
and \d1_8888, \d1_8888, \maskLSR /* 0 |G1*M1| 0 |B1*M1 */
and \scratch6, \scratch6, \maskLSR /* 0 |A2*M2| 0 |R2*M2 */
and \d2_8888, \d2_8888, \maskLSR /* 0 |G2*M2| 0 |B2*M2 */
addq.ph \scratch1, \scratch1, \scratch5
addq.ph \scratch2, \scratch2, \d1_8888
addq.ph \scratch3, \scratch3, \scratch6
addq.ph \scratch4, \scratch4, \d2_8888
shra_r.ph \scratch1, \scratch1, 8
shra_r.ph \scratch2, \scratch2, 8
shra_r.ph \scratch3, \scratch3, 8
shra_r.ph \scratch4, \scratch4, 8
precr.qb.ph \d1_8888, \scratch1, \scratch2
precr.qb.ph \d2_8888, \scratch3, \scratch4
.endm
/*
* Multiply pixel (a8r8g8b8) with single pixel (a8r8g8b8). It requires maskLSR
* needed for rounding process. maskLSR must have following value:
* li maskLSR, 0x00ff00ff
*/
.macro MIPS_UN8x4_MUL_UN8x4 s_8888, \
m_8888, \
d_8888, \
maskLSR, \
scratch1, scratch2, scratch3, scratch4
preceu.ph.qbl \scratch1, \m_8888 /* 0 | A | 0 | R */
preceu.ph.qbr \scratch2, \m_8888 /* 0 | G | 0 | B */
muleu_s.ph.qbl \scratch3, \s_8888, \scratch1 /* A*A | R*R */
muleu_s.ph.qbr \scratch4, \s_8888, \scratch2 /* G*G | B*B */
shra_r.ph \scratch1, \scratch3, 8
shra_r.ph \scratch2, \scratch4, 8
and \scratch1, \scratch1, \maskLSR /* 0 |A*A| 0 |R*R */
and \scratch2, \scratch2, \maskLSR /* 0 |G*G| 0 |B*B */
addq.ph \scratch1, \scratch1, \scratch3
addq.ph \scratch2, \scratch2, \scratch4
shra_r.ph \scratch1, \scratch1, 8
shra_r.ph \scratch2, \scratch2, 8
precr.qb.ph \d_8888, \scratch1, \scratch2
.endm
/*
* Multiply two pixels (a8r8g8b8) with two pixels (a8r8g8b8). It requires
* maskLSR needed for rounding process. maskLSR must have following value:
* li maskLSR, 0x00ff00ff
*/
.macro MIPS_2xUN8x4_MUL_2xUN8x4 s1_8888, \
s2_8888, \
m1_8888, \
m2_8888, \
d1_8888, \
d2_8888, \
maskLSR, \
scratch1, scratch2, scratch3, \
scratch4, scratch5, scratch6
preceu.ph.qbl \scratch1, \m1_8888 /* 0 | A | 0 | R */
preceu.ph.qbr \scratch2, \m1_8888 /* 0 | G | 0 | B */
preceu.ph.qbl \scratch3, \m2_8888 /* 0 | A | 0 | R */
preceu.ph.qbr \scratch4, \m2_8888 /* 0 | G | 0 | B */
muleu_s.ph.qbl \scratch5, \s1_8888, \scratch1 /* A*A | R*R */
muleu_s.ph.qbr \scratch6, \s1_8888, \scratch2 /* G*G | B*B */
muleu_s.ph.qbl \scratch1, \s2_8888, \scratch3 /* A*A | R*R */
muleu_s.ph.qbr \scratch2, \s2_8888, \scratch4 /* G*G | B*B */
shra_r.ph \scratch3, \scratch5, 8
shra_r.ph \scratch4, \scratch6, 8
shra_r.ph \d1_8888, \scratch1, 8
shra_r.ph \d2_8888, \scratch2, 8
and \scratch3, \scratch3, \maskLSR /* 0 |A*A| 0 |R*R */
and \scratch4, \scratch4, \maskLSR /* 0 |G*G| 0 |B*B */
and \d1_8888, \d1_8888, \maskLSR /* 0 |A*A| 0 |R*R */
and \d2_8888, \d2_8888, \maskLSR /* 0 |G*G| 0 |B*B */
addq.ph \scratch3, \scratch3, \scratch5
addq.ph \scratch4, \scratch4, \scratch6
addq.ph \d1_8888, \d1_8888, \scratch1
addq.ph \d2_8888, \d2_8888, \scratch2
shra_r.ph \scratch3, \scratch3, 8
shra_r.ph \scratch4, \scratch4, 8
shra_r.ph \scratch5, \d1_8888, 8
shra_r.ph \scratch6, \d2_8888, 8
precr.qb.ph \d1_8888, \scratch3, \scratch4
precr.qb.ph \d2_8888, \scratch5, \scratch6
.endm
/*
* OVER operation on single a8r8g8b8 source pixel (s_8888) and single a8r8g8b8
* destination pixel (d_8888) using a8 mask (m_8). It also requires maskLSR
* needed for rounding process. maskLSR must have following value:
* li maskLSR, 0x00ff00ff
*/
.macro OVER_8888_8_8888 s_8888, \
m_8, \
d_8888, \
out_8888, \
maskLSR, \
scratch1, scratch2, scratch3, scratch4
MIPS_UN8x4_MUL_UN8 \s_8888, \m_8, \
\scratch1, \maskLSR, \
\scratch2, \scratch3, \scratch4
not \scratch2, \scratch1
srl \scratch2, \scratch2, 24
MIPS_UN8x4_MUL_UN8 \d_8888, \scratch2, \
\d_8888, \maskLSR, \
\scratch3, \scratch4, \out_8888
addu_s.qb \out_8888, \d_8888, \scratch1
.endm
/*
* OVER operation on two a8r8g8b8 source pixels (s1_8888 and s2_8888) and two
* a8r8g8b8 destination pixels (d1_8888 and d2_8888) using a8 masks (m1_8 and
* m2_8). It also requires maskLSR needed for rounding process. maskLSR must
* have following value:
* li maskLSR, 0x00ff00ff
*/
.macro OVER_2x8888_2x8_2x8888 s1_8888, \
s2_8888, \
m1_8, \
m2_8, \
d1_8888, \
d2_8888, \
out1_8888, \
out2_8888, \
maskLSR, \
scratch1, scratch2, scratch3, \
scratch4, scratch5, scratch6
MIPS_2xUN8x4_MUL_2xUN8 \s1_8888, \s2_8888, \
\m1_8, \m2_8, \
\scratch1, \scratch2, \
\maskLSR, \
\scratch3, \scratch4, \out1_8888, \
\out2_8888, \scratch5, \scratch6
not \scratch3, \scratch1
srl \scratch3, \scratch3, 24
not \scratch4, \scratch2
srl \scratch4, \scratch4, 24
MIPS_2xUN8x4_MUL_2xUN8 \d1_8888, \d2_8888, \
\scratch3, \scratch4, \
\d1_8888, \d2_8888, \
\maskLSR, \
\scratch5, \scratch6, \out1_8888, \
\out2_8888, \scratch3, \scratch4
addu_s.qb \out1_8888, \d1_8888, \scratch1
addu_s.qb \out2_8888, \d2_8888, \scratch2
.endm
/*
* OVER operation on single a8r8g8b8 source pixel (s_8888) and single a8r8g8b8
* destination pixel (d_8888). It also requires maskLSR needed for rounding
* process. maskLSR must have following value:
* li maskLSR, 0x00ff00ff
*/
.macro OVER_8888_8888 s_8888, \
d_8888, \
out_8888, \
maskLSR, \
scratch1, scratch2, scratch3, scratch4
not \scratch1, \s_8888
srl \scratch1, \scratch1, 24
MIPS_UN8x4_MUL_UN8 \d_8888, \scratch1, \
\out_8888, \maskLSR, \
\scratch2, \scratch3, \scratch4
addu_s.qb \out_8888, \out_8888, \s_8888
.endm
.macro MIPS_UN8x4_MUL_UN8_ADD_UN8x4 s_8888, \
m_8, \
d_8888, \
out_8888, \
maskLSR, \
scratch1, scratch2, scratch3
MIPS_UN8x4_MUL_UN8 \s_8888, \m_8, \
\out_8888, \maskLSR, \
\scratch1, \scratch2, \scratch3
addu_s.qb \out_8888, \out_8888, \d_8888
.endm
.macro MIPS_2xUN8x4_MUL_2xUN8_ADD_2xUN8x4 s1_8888, \
s2_8888, \
m1_8, \
m2_8, \
d1_8888, \
d2_8888, \
out1_8888, \
out2_8888, \
maskLSR, \
scratch1, scratch2, scratch3, \
scratch4, scratch5, scratch6
MIPS_2xUN8x4_MUL_2xUN8 \s1_8888, \s2_8888, \
\m1_8, \m2_8, \
\out1_8888, \out2_8888, \
\maskLSR, \
\scratch1, \scratch2, \scratch3, \
\scratch4, \scratch5, \scratch6
addu_s.qb \out1_8888, \out1_8888, \d1_8888
addu_s.qb \out2_8888, \out2_8888, \d2_8888
.endm
.macro BILINEAR_INTERPOLATE_SINGLE_PIXEL tl, tr, bl, br, \
scratch1, scratch2, \
alpha, red, green, blue \
wt1, wt2, wb1, wb2
andi \scratch1, \tl, 0xff
andi \scratch2, \tr, 0xff
andi \alpha, \bl, 0xff
andi \red, \br, 0xff
multu $ac0, \wt1, \scratch1
maddu $ac0, \wt2, \scratch2
maddu $ac0, \wb1, \alpha
maddu $ac0, \wb2, \red
ext \scratch1, \tl, 8, 8
ext \scratch2, \tr, 8, 8
ext \alpha, \bl, 8, 8
ext \red, \br, 8, 8
multu $ac1, \wt1, \scratch1
maddu $ac1, \wt2, \scratch2
maddu $ac1, \wb1, \alpha
maddu $ac1, \wb2, \red
ext \scratch1, \tl, 16, 8
ext \scratch2, \tr, 16, 8
ext \alpha, \bl, 16, 8
ext \red, \br, 16, 8
mflo \blue, $ac0
multu $ac2, \wt1, \scratch1
maddu $ac2, \wt2, \scratch2
maddu $ac2, \wb1, \alpha
maddu $ac2, \wb2, \red
ext \scratch1, \tl, 24, 8
ext \scratch2, \tr, 24, 8
ext \alpha, \bl, 24, 8
ext \red, \br, 24, 8
mflo \green, $ac1
multu $ac3, \wt1, \scratch1
maddu $ac3, \wt2, \scratch2
maddu $ac3, \wb1, \alpha
maddu $ac3, \wb2, \red
mflo \red, $ac2
mflo \alpha, $ac3
precr.qb.ph \alpha, \alpha, \red
precr.qb.ph \scratch1, \green, \blue
precrq.qb.ph \tl, \alpha, \scratch1
.endm
#endif //PIXMAN_MIPS_DSPR2_ASM_H

View file

@ -0,0 +1,411 @@
/*
* Copyright (c) 2012
* MIPS Technologies, Inc., California.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Author: Nemanja Lukic (nlukic@mips.com)
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "pixman-private.h"
#include "pixman-mips-dspr2.h"
PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, src_x888_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, src_8888_0565,
uint32_t, 1, uint16_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, src_0565_8888,
uint16_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (DO_FAST_MEMCPY, src_0565_0565,
uint16_t, 1, uint16_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (DO_FAST_MEMCPY, src_8888_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (DO_FAST_MEMCPY, src_0888_0888,
uint8_t, 3, uint8_t, 3)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, over_8888_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, add_8_8,
uint8_t, 1, uint8_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, add_8888_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, out_reverse_8_0565,
uint8_t, 1, uint16_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST (0, out_reverse_8_8888,
uint8_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (0, src_n_8_8888,
uint8_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (0, src_n_8_8,
uint8_t, 1, uint8_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, over_n_8888_8888_ca,
uint32_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, over_n_8888_0565_ca,
uint32_t, 1, uint16_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, over_n_8_8888,
uint8_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, over_n_8_0565,
uint8_t, 1, uint16_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, add_n_8_8,
uint8_t, 1, uint8_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST (SKIP_ZERO_SRC, add_n_8_8888,
uint8_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, over_8888_n_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, over_8888_n_0565,
uint32_t, 1, uint16_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, over_0565_n_0565,
uint16_t, 1, uint16_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_N_DST (SKIP_ZERO_MASK, add_8888_n_8888,
uint32_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_N_DST (SKIP_ZERO_SRC, over_n_0565,
uint16_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_N_DST (SKIP_ZERO_SRC, over_n_8888,
uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_N_DST (SKIP_ZERO_SRC, over_reverse_n_8888,
uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_N_DST (0, in_n_8,
uint8_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_MASK_DST (add_8_8_8, uint8_t, 1,
uint8_t, 1, uint8_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_MASK_DST (add_8888_8_8888, uint32_t, 1,
uint8_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_MASK_DST (add_8888_8888_8888, uint32_t, 1,
uint32_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_MASK_DST (add_0565_8_0565, uint16_t, 1,
uint8_t, 1, uint16_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_MASK_DST (over_8888_8_8888, uint32_t, 1,
uint8_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_MASK_DST (over_8888_8_0565, uint32_t, 1,
uint8_t, 1, uint16_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_MASK_DST (over_0565_8_0565, uint16_t, 1,
uint8_t, 1, uint16_t, 1)
PIXMAN_MIPS_BIND_FAST_PATH_SRC_MASK_DST (over_8888_8888_8888, uint32_t, 1,
uint32_t, 1, uint32_t, 1)
PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_DST (0, 8888_8888, SRC,
uint32_t, uint32_t)
PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_DST (0, 8888_0565, SRC,
uint32_t, uint16_t)
PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_DST (0, 0565_8888, SRC,
uint16_t, uint32_t)
PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_DST (0, 0565_0565, SRC,
uint16_t, uint16_t)
PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_DST (SKIP_ZERO_SRC, 8888_8888, OVER,
uint32_t, uint32_t)
PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_DST (SKIP_ZERO_SRC, 8888_8888, ADD,
uint32_t, uint32_t)
PIXMAN_MIPS_BIND_SCALED_NEAREST_SRC_A8_DST (SKIP_ZERO_SRC, 8888_8_0565,
OVER, uint32_t, uint16_t)
PIXMAN_MIPS_BIND_SCALED_NEAREST_SRC_A8_DST (SKIP_ZERO_SRC, 0565_8_0565,
OVER, uint16_t, uint16_t)
PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_A8_DST (0, 8888_8_8888, SRC,
uint32_t, uint32_t)
PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_A8_DST (0, 8888_8_0565, SRC,
uint32_t, uint16_t)
PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_A8_DST (0, 0565_8_x888, SRC,
uint16_t, uint32_t)
PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_A8_DST (0, 0565_8_0565, SRC,
uint16_t, uint16_t)
PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_A8_DST (SKIP_ZERO_SRC, 8888_8_8888, OVER,
uint32_t, uint32_t)
PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_A8_DST (SKIP_ZERO_SRC, 8888_8_8888, ADD,
uint32_t, uint32_t)
static pixman_bool_t
mips_dspr2_fill (pixman_implementation_t *imp,
uint32_t * bits,
int stride,
int bpp,
int x,
int y,
int width,
int height,
uint32_t _xor)
{
uint8_t *byte_line;
uint32_t byte_width;
switch (bpp)
{
case 16:
stride = stride * (int) sizeof (uint32_t) / 2;
byte_line = (uint8_t *)(((uint16_t *)bits) + stride * y + x);
byte_width = width * 2;
stride *= 2;
while (height--)
{
uint8_t *dst = byte_line;
byte_line += stride;
pixman_fill_buff16_mips (dst, byte_width, _xor & 0xffff);
}
return TRUE;
case 32:
stride = stride * (int) sizeof (uint32_t) / 4;
byte_line = (uint8_t *)(((uint32_t *)bits) + stride * y + x);
byte_width = width * 4;
stride *= 4;
while (height--)
{
uint8_t *dst = byte_line;
byte_line += stride;
pixman_fill_buff32_mips (dst, byte_width, _xor);
}
return TRUE;
default:
return FALSE;
}
}
static pixman_bool_t
mips_dspr2_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 dest_x,
int dest_y,
int width,
int height)
{
if (src_bpp != dst_bpp)
return FALSE;
uint8_t *src_bytes;
uint8_t *dst_bytes;
uint32_t byte_width;
switch (src_bpp)
{
case 16:
src_stride = src_stride * (int) sizeof (uint32_t) / 2;
dst_stride = dst_stride * (int) sizeof (uint32_t) / 2;
src_bytes =(uint8_t *)(((uint16_t *)src_bits)
+ src_stride * (src_y) + (src_x));
dst_bytes = (uint8_t *)(((uint16_t *)dst_bits)
+ dst_stride * (dest_y) + (dest_x));
byte_width = width * 2;
src_stride *= 2;
dst_stride *= 2;
while (height--)
{
uint8_t *src = src_bytes;
uint8_t *dst = dst_bytes;
src_bytes += src_stride;
dst_bytes += dst_stride;
pixman_mips_fast_memcpy (dst, src, byte_width);
}
return TRUE;
case 32:
src_stride = src_stride * (int) sizeof (uint32_t) / 4;
dst_stride = dst_stride * (int) sizeof (uint32_t) / 4;
src_bytes = (uint8_t *)(((uint32_t *)src_bits)
+ src_stride * (src_y) + (src_x));
dst_bytes = (uint8_t *)(((uint32_t *)dst_bits)
+ dst_stride * (dest_y) + (dest_x));
byte_width = width * 4;
src_stride *= 4;
dst_stride *= 4;
while (height--)
{
uint8_t *src = src_bytes;
uint8_t *dst = dst_bytes;
src_bytes += src_stride;
dst_bytes += dst_stride;
pixman_mips_fast_memcpy (dst, src, byte_width);
}
return TRUE;
default:
return FALSE;
}
}
static const pixman_fast_path_t mips_dspr2_fast_paths[] =
{
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, r5g6b5, mips_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, b5g6r5, mips_composite_src_0565_0565),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, r5g6b5, mips_composite_src_8888_0565),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, r5g6b5, mips_composite_src_8888_0565),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, b5g6r5, mips_composite_src_8888_0565),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, b5g6r5, mips_composite_src_8888_0565),
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, a8r8g8b8, mips_composite_src_0565_8888),
PIXMAN_STD_FAST_PATH (SRC, r5g6b5, null, x8r8g8b8, mips_composite_src_0565_8888),
PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, a8b8g8r8, mips_composite_src_0565_8888),
PIXMAN_STD_FAST_PATH (SRC, b5g6r5, null, x8b8g8r8, mips_composite_src_0565_8888),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, x8r8g8b8, mips_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, x8r8g8b8, mips_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, x8b8g8r8, mips_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, x8b8g8r8, mips_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, a8r8g8b8, null, a8r8g8b8, mips_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, a8b8g8r8, null, a8b8g8r8, mips_composite_src_8888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8r8g8b8, null, a8r8g8b8, mips_composite_src_x888_8888),
PIXMAN_STD_FAST_PATH (SRC, x8b8g8r8, null, a8b8g8r8, mips_composite_src_x888_8888),
PIXMAN_STD_FAST_PATH (SRC, r8g8b8, null, r8g8b8, mips_composite_src_0888_0888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, a8r8g8b8, mips_composite_src_n_8_8888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, x8r8g8b8, mips_composite_src_n_8_8888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, a8b8g8r8, mips_composite_src_n_8_8888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, x8b8g8r8, mips_composite_src_n_8_8888),
PIXMAN_STD_FAST_PATH (SRC, solid, a8, a8, mips_composite_src_n_8_8),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, a8r8g8b8, mips_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, x8r8g8b8, mips_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, a8b8g8r8, mips_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, x8b8g8r8, mips_composite_over_n_8888_8888_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8r8g8b8, r5g6b5, mips_composite_over_n_8888_0565_ca),
PIXMAN_STD_FAST_PATH_CA (OVER, solid, a8b8g8r8, b5g6r5, mips_composite_over_n_8888_0565_ca),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8r8g8b8, mips_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8r8g8b8, mips_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, a8b8g8r8, mips_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, x8b8g8r8, mips_composite_over_n_8_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, r5g6b5, mips_composite_over_n_8_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, a8, b5g6r5, mips_composite_over_n_8_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, null, r5g6b5, mips_composite_over_n_0565),
PIXMAN_STD_FAST_PATH (OVER, solid, null, a8r8g8b8, mips_composite_over_n_8888),
PIXMAN_STD_FAST_PATH (OVER, solid, null, x8r8g8b8, mips_composite_over_n_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, a8r8g8b8, mips_composite_over_8888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, x8r8g8b8, mips_composite_over_8888_n_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, solid, r5g6b5, mips_composite_over_8888_n_0565),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, solid, b5g6r5, mips_composite_over_8888_n_0565),
PIXMAN_STD_FAST_PATH (OVER, r5g6b5, solid, r5g6b5, mips_composite_over_0565_n_0565),
PIXMAN_STD_FAST_PATH (OVER, b5g6r5, solid, b5g6r5, mips_composite_over_0565_n_0565),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8, a8r8g8b8, mips_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8, x8r8g8b8, mips_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, a8, a8b8g8r8, mips_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, a8, x8b8g8r8, mips_composite_over_8888_8_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8, r5g6b5, mips_composite_over_8888_8_0565),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, a8, b5g6r5, mips_composite_over_8888_8_0565),
PIXMAN_STD_FAST_PATH (OVER, r5g6b5, a8, r5g6b5, mips_composite_over_0565_8_0565),
PIXMAN_STD_FAST_PATH (OVER, b5g6r5, a8, b5g6r5, mips_composite_over_0565_8_0565),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, a8r8g8b8, mips_composite_over_8888_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, a8r8g8b8, mips_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8r8g8b8, null, x8r8g8b8, mips_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, a8b8g8r8, mips_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (OVER, a8b8g8r8, null, x8b8g8r8, mips_composite_over_8888_8888),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8, mips_composite_add_n_8_8),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8r8g8b8, mips_composite_add_n_8_8888),
PIXMAN_STD_FAST_PATH (ADD, solid, a8, a8b8g8r8, mips_composite_add_n_8_8888),
PIXMAN_STD_FAST_PATH (ADD, a8, a8, a8, mips_composite_add_8_8_8),
PIXMAN_STD_FAST_PATH (ADD, r5g6b5, a8, r5g6b5, mips_composite_add_0565_8_0565),
PIXMAN_STD_FAST_PATH (ADD, b5g6r5, a8, b5g6r5, mips_composite_add_0565_8_0565),
PIXMAN_STD_FAST_PATH (ADD, a8r8g8b8, a8, a8r8g8b8, mips_composite_add_8888_8_8888),
PIXMAN_STD_FAST_PATH (ADD, a8b8g8r8, a8, a8b8g8r8, mips_composite_add_8888_8_8888),
PIXMAN_STD_FAST_PATH (ADD, a8r8g8b8, a8r8g8b8, a8r8g8b8, mips_composite_add_8888_8888_8888),
PIXMAN_STD_FAST_PATH (ADD, a8r8g8b8, solid, a8r8g8b8, mips_composite_add_8888_n_8888),
PIXMAN_STD_FAST_PATH (ADD, a8b8g8r8, solid, a8b8g8r8, mips_composite_add_8888_n_8888),
PIXMAN_STD_FAST_PATH (ADD, a8, null, a8, mips_composite_add_8_8),
PIXMAN_STD_FAST_PATH (ADD, a8r8g8b8, null, a8r8g8b8, mips_composite_add_8888_8888),
PIXMAN_STD_FAST_PATH (ADD, a8b8g8r8, null, a8b8g8r8, mips_composite_add_8888_8888),
PIXMAN_STD_FAST_PATH (OUT_REVERSE, a8, null, r5g6b5, mips_composite_out_reverse_8_0565),
PIXMAN_STD_FAST_PATH (OUT_REVERSE, a8, null, b5g6r5, mips_composite_out_reverse_8_0565),
PIXMAN_STD_FAST_PATH (OUT_REVERSE, a8, null, a8r8g8b8, mips_composite_out_reverse_8_8888),
PIXMAN_STD_FAST_PATH (OUT_REVERSE, a8, null, a8b8g8r8, mips_composite_out_reverse_8_8888),
PIXMAN_STD_FAST_PATH (OVER_REVERSE, solid, null, a8r8g8b8, mips_composite_over_reverse_n_8888),
PIXMAN_STD_FAST_PATH (OVER_REVERSE, solid, null, a8b8g8r8, mips_composite_over_reverse_n_8888),
PIXMAN_STD_FAST_PATH (IN, solid, null, a8, mips_composite_in_n_8),
PIXMAN_MIPS_SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, a8r8g8b8, r5g6b5, mips_8888_8_0565),
PIXMAN_MIPS_SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, a8b8g8r8, b5g6r5, mips_8888_8_0565),
PIXMAN_MIPS_SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, r5g6b5, r5g6b5, mips_0565_8_0565),
PIXMAN_MIPS_SIMPLE_NEAREST_A8_MASK_FAST_PATH (OVER, b5g6r5, b5g6r5, mips_0565_8_0565),
SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, mips_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, mips_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, mips_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, r5g6b5, mips_8888_0565),
SIMPLE_BILINEAR_FAST_PATH (SRC, x8r8g8b8, r5g6b5, mips_8888_0565),
SIMPLE_BILINEAR_FAST_PATH (SRC, r5g6b5, x8r8g8b8, mips_0565_8888),
SIMPLE_BILINEAR_FAST_PATH (SRC, r5g6b5, r5g6b5, mips_0565_0565),
SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, mips_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, mips_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (ADD, a8r8g8b8, a8r8g8b8, mips_8888_8888),
SIMPLE_BILINEAR_FAST_PATH (ADD, a8r8g8b8, x8r8g8b8, mips_8888_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, mips_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, mips_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, mips_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, a8r8g8b8, r5g6b5, mips_8888_8_0565),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, x8r8g8b8, r5g6b5, mips_8888_8_0565),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, r5g6b5, x8r8g8b8, mips_0565_8_x888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (SRC, r5g6b5, r5g6b5, mips_0565_8_0565),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, mips_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, mips_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (ADD, a8r8g8b8, a8r8g8b8, mips_8888_8_8888),
SIMPLE_BILINEAR_A8_MASK_FAST_PATH (ADD, a8r8g8b8, x8r8g8b8, mips_8888_8_8888),
{ PIXMAN_OP_NONE },
};
static void
mips_dspr2_combine_over_u (pixman_implementation_t *imp,
pixman_op_t op,
uint32_t * dest,
const uint32_t * src,
const uint32_t * mask,
int width)
{
if (mask)
pixman_composite_over_8888_8888_8888_asm_mips (
dest, (uint32_t *)src, (uint32_t *)mask, width);
else
pixman_composite_over_8888_8888_asm_mips (
dest, (uint32_t *)src, width);
}
pixman_implementation_t *
_pixman_implementation_create_mips_dspr2 (pixman_implementation_t *fallback)
{
pixman_implementation_t *imp =
_pixman_implementation_create (fallback, mips_dspr2_fast_paths);
imp->combine_32[PIXMAN_OP_OVER] = mips_dspr2_combine_over_u;
imp->blt = mips_dspr2_blt;
imp->fill = mips_dspr2_fill;
return imp;
}

View file

@ -0,0 +1,396 @@
/*
* Copyright (c) 2012
* MIPS Technologies, Inc., California.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Author: Nemanja Lukic (nlukic@mips.com)
*/
#ifndef PIXMAN_MIPS_DSPR2_H
#define PIXMAN_MIPS_DSPR2_H
#include "pixman-private.h"
#include "pixman-inlines.h"
#define SKIP_ZERO_SRC 1
#define SKIP_ZERO_MASK 2
#define DO_FAST_MEMCPY 3
void
pixman_mips_fast_memcpy (void *dst, void *src, uint32_t n_bytes);
void
pixman_fill_buff16_mips (void *dst, uint32_t n_bytes, uint16_t value);
void
pixman_fill_buff32_mips (void *dst, uint32_t n_bytes, uint32_t value);
/****************************************************************/
#define PIXMAN_MIPS_BIND_FAST_PATH_SRC_DST(flags, name, \
src_type, src_cnt, \
dst_type, dst_cnt) \
void \
pixman_composite_##name##_asm_mips (dst_type *dst, \
src_type *src, \
int32_t w); \
\
static void \
mips_composite_##name (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
dst_type *dst_line, *dst; \
src_type *src_line, *src; \
int32_t dst_stride, src_stride; \
int bpp = PIXMAN_FORMAT_BPP (dest_image->bits.format) / 8; \
\
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, src_type, \
src_stride, src_line, src_cnt); \
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type, \
dst_stride, dst_line, dst_cnt); \
\
while (height--) \
{ \
dst = dst_line; \
dst_line += dst_stride; \
src = src_line; \
src_line += src_stride; \
\
if (flags == DO_FAST_MEMCPY) \
pixman_mips_fast_memcpy (dst, src, width * bpp); \
else \
pixman_composite_##name##_asm_mips (dst, src, width); \
} \
}
/****************************************************************/
#define PIXMAN_MIPS_BIND_FAST_PATH_N_DST(flags, name, \
dst_type, dst_cnt) \
void \
pixman_composite_##name##_asm_mips (dst_type *dst, \
uint32_t src, \
int32_t w); \
\
static void \
mips_composite_##name (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
dst_type *dst_line, *dst; \
int32_t dst_stride; \
uint32_t src; \
\
src = _pixman_image_get_solid ( \
imp, src_image, dest_image->bits.format); \
\
if ((flags & SKIP_ZERO_SRC) && src == 0) \
return; \
\
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type, \
dst_stride, dst_line, dst_cnt); \
\
while (height--) \
{ \
dst = dst_line; \
dst_line += dst_stride; \
\
pixman_composite_##name##_asm_mips (dst, src, width); \
} \
}
/*******************************************************************/
#define PIXMAN_MIPS_BIND_FAST_PATH_N_MASK_DST(flags, name, \
mask_type, mask_cnt, \
dst_type, dst_cnt) \
void \
pixman_composite_##name##_asm_mips (dst_type *dst, \
uint32_t src, \
mask_type *mask, \
int32_t w); \
\
static void \
mips_composite_##name (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
dst_type *dst_line, *dst; \
mask_type *mask_line, *mask; \
int32_t dst_stride, mask_stride; \
uint32_t src; \
\
src = _pixman_image_get_solid ( \
imp, src_image, dest_image->bits.format); \
\
if ((flags & SKIP_ZERO_SRC) && src == 0) \
return; \
\
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type, \
dst_stride, dst_line, dst_cnt); \
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, mask_type, \
mask_stride, mask_line, mask_cnt); \
\
while (height--) \
{ \
dst = dst_line; \
dst_line += dst_stride; \
mask = mask_line; \
mask_line += mask_stride; \
pixman_composite_##name##_asm_mips (dst, src, mask, width); \
} \
}
/*******************************************************************/
#define PIXMAN_MIPS_BIND_FAST_PATH_SRC_N_DST(flags, name, \
src_type, src_cnt, \
dst_type, dst_cnt) \
void \
pixman_composite_##name##_asm_mips (dst_type *dst, \
src_type *src, \
uint32_t mask, \
int32_t w); \
\
static void \
mips_composite_##name (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
dst_type *dst_line, *dst; \
src_type *src_line, *src; \
int32_t dst_stride, src_stride; \
uint32_t mask; \
\
mask = _pixman_image_get_solid ( \
imp, mask_image, dest_image->bits.format); \
\
if ((flags & SKIP_ZERO_MASK) && mask == 0) \
return; \
\
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type, \
dst_stride, dst_line, dst_cnt); \
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, src_type, \
src_stride, src_line, src_cnt); \
\
while (height--) \
{ \
dst = dst_line; \
dst_line += dst_stride; \
src = src_line; \
src_line += src_stride; \
\
pixman_composite_##name##_asm_mips (dst, src, mask, width); \
} \
}
/************************************************************************/
#define PIXMAN_MIPS_BIND_FAST_PATH_SRC_MASK_DST(name, src_type, src_cnt, \
mask_type, mask_cnt, \
dst_type, dst_cnt) \
void \
pixman_composite_##name##_asm_mips (dst_type *dst, \
src_type *src, \
mask_type *mask, \
int32_t w); \
\
static void \
mips_composite_##name (pixman_implementation_t *imp, \
pixman_composite_info_t *info) \
{ \
PIXMAN_COMPOSITE_ARGS (info); \
dst_type *dst_line, *dst; \
src_type *src_line, *src; \
mask_type *mask_line, *mask; \
int32_t dst_stride, src_stride, mask_stride; \
\
PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type, \
dst_stride, dst_line, dst_cnt); \
PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, src_type, \
src_stride, src_line, src_cnt); \
PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, mask_type, \
mask_stride, mask_line, mask_cnt); \
\
while (height--) \
{ \
dst = dst_line; \
dst_line += dst_stride; \
mask = mask_line; \
mask_line += mask_stride; \
src = src_line; \
src_line += src_stride; \
pixman_composite_##name##_asm_mips (dst, src, mask, width); \
} \
}
/*****************************************************************************/
#define PIXMAN_MIPS_BIND_SCALED_NEAREST_SRC_A8_DST(flags, name, op, \
src_type, dst_type) \
void \
pixman_scaled_nearest_scanline_##name##_##op##_asm_mips ( \
dst_type * dst, \
const src_type * src, \
const uint8_t * mask, \
int32_t w, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x); \
\
static force_inline void \
scaled_nearest_scanline_mips_##name##_##op (const uint8_t * mask, \
dst_type * pd, \
const src_type * ps, \
int32_t w, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x, \
pixman_fixed_t max_vx, \
pixman_bool_t zero_src) \
{ \
if ((flags & SKIP_ZERO_SRC) && zero_src) \
return; \
pixman_scaled_nearest_scanline_##name##_##op##_asm_mips (pd, ps, \
mask, w, \
vx, unit_x); \
} \
\
FAST_NEAREST_MAINLOOP_COMMON (mips_##name##_cover_##op, \
scaled_nearest_scanline_mips_##name##_##op, \
src_type, uint8_t, dst_type, COVER, TRUE, FALSE)\
FAST_NEAREST_MAINLOOP_COMMON (mips_##name##_none_##op, \
scaled_nearest_scanline_mips_##name##_##op, \
src_type, uint8_t, dst_type, NONE, TRUE, FALSE) \
FAST_NEAREST_MAINLOOP_COMMON (mips_##name##_pad_##op, \
scaled_nearest_scanline_mips_##name##_##op, \
src_type, uint8_t, dst_type, PAD, TRUE, FALSE)
/* Provide entries for the fast path table */
#define PIXMAN_MIPS_SIMPLE_NEAREST_A8_MASK_FAST_PATH(op,s,d,func) \
SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER (op,s,d,func), \
SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE (op,s,d,func), \
SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD (op,s,d,func)
/****************************************************************************/
#define PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_DST(flags, name, op, \
src_type, dst_type) \
void \
pixman_scaled_bilinear_scanline_##name##_##op##_asm_mips( \
dst_type * dst, \
const src_type * src_top, \
const src_type * src_bottom, \
int32_t w, \
int wt, \
int wb, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x); \
static force_inline void \
scaled_bilinear_scanline_mips_##name##_##op (dst_type * dst, \
const uint32_t * mask, \
const src_type * src_top, \
const src_type * src_bottom, \
int32_t w, \
int wt, \
int wb, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x, \
pixman_fixed_t max_vx, \
pixman_bool_t zero_src) \
{ \
if ((flags & SKIP_ZERO_SRC) && zero_src) \
return; \
pixman_scaled_bilinear_scanline_##name##_##op##_asm_mips (dst, src_top, \
src_bottom, w, \
wt, wb, \
vx, unit_x); \
} \
\
FAST_BILINEAR_MAINLOOP_COMMON (mips_##name##_cover_##op, \
scaled_bilinear_scanline_mips_##name##_##op, \
src_type, uint32_t, dst_type, COVER, FLAG_NONE) \
FAST_BILINEAR_MAINLOOP_COMMON (mips_##name##_none_##op, \
scaled_bilinear_scanline_mips_##name##_##op, \
src_type, uint32_t, dst_type, NONE, FLAG_NONE) \
FAST_BILINEAR_MAINLOOP_COMMON (mips_##name##_pad_##op, \
scaled_bilinear_scanline_mips_##name##_##op, \
src_type, uint32_t, dst_type, PAD, FLAG_NONE) \
FAST_BILINEAR_MAINLOOP_COMMON (mips_##name##_normal_##op, \
scaled_bilinear_scanline_mips_##name##_##op, \
src_type, uint32_t, dst_type, NORMAL, \
FLAG_NONE)
/*****************************************************************************/
#define PIXMAN_MIPS_BIND_SCALED_BILINEAR_SRC_A8_DST(flags, name, op, \
src_type, dst_type) \
void \
pixman_scaled_bilinear_scanline_##name##_##op##_asm_mips ( \
dst_type * dst, \
const uint8_t * mask, \
const src_type * top, \
const src_type * bottom, \
int wt, \
int wb, \
pixman_fixed_t x, \
pixman_fixed_t ux, \
int width); \
\
static force_inline void \
scaled_bilinear_scanline_mips_##name##_##op (dst_type * dst, \
const uint8_t * mask, \
const src_type * src_top, \
const src_type * src_bottom, \
int32_t w, \
int wt, \
int wb, \
pixman_fixed_t vx, \
pixman_fixed_t unit_x, \
pixman_fixed_t max_vx, \
pixman_bool_t zero_src) \
{ \
if ((flags & SKIP_ZERO_SRC) && zero_src) \
return; \
pixman_scaled_bilinear_scanline_##name##_##op##_asm_mips ( \
dst, mask, src_top, src_bottom, wt, wb, vx, unit_x, w); \
} \
\
FAST_BILINEAR_MAINLOOP_COMMON (mips_##name##_cover_##op, \
scaled_bilinear_scanline_mips_##name##_##op, \
src_type, uint8_t, dst_type, COVER, \
FLAG_HAVE_NON_SOLID_MASK) \
FAST_BILINEAR_MAINLOOP_COMMON (mips_##name##_none_##op, \
scaled_bilinear_scanline_mips_##name##_##op, \
src_type, uint8_t, dst_type, NONE, \
FLAG_HAVE_NON_SOLID_MASK) \
FAST_BILINEAR_MAINLOOP_COMMON (mips_##name##_pad_##op, \
scaled_bilinear_scanline_mips_##name##_##op, \
src_type, uint8_t, dst_type, PAD, \
FLAG_HAVE_NON_SOLID_MASK) \
FAST_BILINEAR_MAINLOOP_COMMON (mips_##name##_normal_##op, \
scaled_bilinear_scanline_mips_##name##_##op, \
src_type, uint8_t, dst_type, NORMAL, \
FLAG_HAVE_NON_SOLID_MASK)
#endif //PIXMAN_MIPS_DSPR2_H

View file

@ -0,0 +1,382 @@
/*
* Copyright (c) 2012
* MIPS Technologies, Inc., California.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "pixman-mips-dspr2-asm.h"
/*
* This routine could be optimized for MIPS64. The current code only
* uses MIPS32 instructions.
*/
#ifdef EB
# define LWHI lwl /* high part is left in big-endian */
# define SWHI swl /* high part is left in big-endian */
# define LWLO lwr /* low part is right in big-endian */
# define SWLO swr /* low part is right in big-endian */
#else
# define LWHI lwr /* high part is right in little-endian */
# define SWHI swr /* high part is right in little-endian */
# define LWLO lwl /* low part is left in big-endian */
# define SWLO swl /* low part is left in big-endian */
#endif
LEAF_MIPS32R2(pixman_mips_fast_memcpy)
slti AT, a2, 8
bne AT, zero, $last8
move v0, a0 /* memcpy returns the dst pointer */
/* Test if the src and dst are word-aligned, or can be made word-aligned */
xor t8, a1, a0
andi t8, t8, 0x3 /* t8 is a0/a1 word-displacement */
bne t8, zero, $unaligned
negu a3, a0
andi a3, a3, 0x3 /* we need to copy a3 bytes to make a0/a1 aligned */
beq a3, zero, $chk16w /* when a3=0 then the dst (a0) is word-aligned */
subu a2, a2, a3 /* now a2 is the remining bytes count */
LWHI t8, 0(a1)
addu a1, a1, a3
SWHI t8, 0(a0)
addu a0, a0, a3
/* Now the dst/src are mutually word-aligned with word-aligned addresses */
$chk16w: andi t8, a2, 0x3f /* any whole 64-byte chunks? */
/* t8 is the byte count after 64-byte chunks */
beq a2, t8, $chk8w /* if a2==t8, no 64-byte chunks */
/* There will be at most 1 32-byte chunk after it */
subu a3, a2, t8 /* subtract from a2 the reminder */
/* Here a3 counts bytes in 16w chunks */
addu a3, a0, a3 /* Now a3 is the final dst after 64-byte chunks */
addu t0, a0, a2 /* t0 is the "past the end" address */
/*
* When in the loop we exercise "pref 30, x(a0)", the a0+x should not be past
* the "t0-32" address
* This means: for x=128 the last "safe" a0 address is "t0-160"
* Alternatively, for x=64 the last "safe" a0 address is "t0-96"
* In the current version we use "pref 30, 128(a0)", so "t0-160" is the limit
*/
subu t9, t0, 160 /* t9 is the "last safe pref 30, 128(a0)" address */
pref 0, 0(a1) /* bring the first line of src, addr 0 */
pref 0, 32(a1) /* bring the second line of src, addr 32 */
pref 0, 64(a1) /* bring the third line of src, addr 64 */
pref 30, 32(a0) /* safe, as we have at least 64 bytes ahead */
/* In case the a0 > t9 don't use "pref 30" at all */
sgtu v1, a0, t9
bgtz v1, $loop16w /* skip "pref 30, 64(a0)" for too short arrays */
nop
/* otherwise, start with using pref30 */
pref 30, 64(a0)
$loop16w:
pref 0, 96(a1)
lw t0, 0(a1)
bgtz v1, $skip_pref30_96 /* skip "pref 30, 96(a0)" */
lw t1, 4(a1)
pref 30, 96(a0) /* continue setting up the dest, addr 96 */
$skip_pref30_96:
lw t2, 8(a1)
lw t3, 12(a1)
lw t4, 16(a1)
lw t5, 20(a1)
lw t6, 24(a1)
lw t7, 28(a1)
pref 0, 128(a1) /* bring the next lines of src, addr 128 */
sw t0, 0(a0)
sw t1, 4(a0)
sw t2, 8(a0)
sw t3, 12(a0)
sw t4, 16(a0)
sw t5, 20(a0)
sw t6, 24(a0)
sw t7, 28(a0)
lw t0, 32(a1)
bgtz v1, $skip_pref30_128 /* skip "pref 30, 128(a0)" */
lw t1, 36(a1)
pref 30, 128(a0) /* continue setting up the dest, addr 128 */
$skip_pref30_128:
lw t2, 40(a1)
lw t3, 44(a1)
lw t4, 48(a1)
lw t5, 52(a1)
lw t6, 56(a1)
lw t7, 60(a1)
pref 0, 160(a1) /* bring the next lines of src, addr 160 */
sw t0, 32(a0)
sw t1, 36(a0)
sw t2, 40(a0)
sw t3, 44(a0)
sw t4, 48(a0)
sw t5, 52(a0)
sw t6, 56(a0)
sw t7, 60(a0)
addiu a0, a0, 64 /* adding 64 to dest */
sgtu v1, a0, t9
bne a0, a3, $loop16w
addiu a1, a1, 64 /* adding 64 to src */
move a2, t8
/* Here we have src and dest word-aligned but less than 64-bytes to go */
$chk8w:
pref 0, 0x0(a1)
andi t8, a2, 0x1f /* is there a 32-byte chunk? */
/* the t8 is the reminder count past 32-bytes */
beq a2, t8, $chk1w /* when a2=t8, no 32-byte chunk */
nop
lw t0, 0(a1)
lw t1, 4(a1)
lw t2, 8(a1)
lw t3, 12(a1)
lw t4, 16(a1)
lw t5, 20(a1)
lw t6, 24(a1)
lw t7, 28(a1)
addiu a1, a1, 32
sw t0, 0(a0)
sw t1, 4(a0)
sw t2, 8(a0)
sw t3, 12(a0)
sw t4, 16(a0)
sw t5, 20(a0)
sw t6, 24(a0)
sw t7, 28(a0)
addiu a0, a0, 32
$chk1w:
andi a2, t8, 0x3 /* now a2 is the reminder past 1w chunks */
beq a2, t8, $last8
subu a3, t8, a2 /* a3 is count of bytes in 1w chunks */
addu a3, a0, a3 /* now a3 is the dst address past the 1w chunks */
/* copying in words (4-byte chunks) */
$wordCopy_loop:
lw t3, 0(a1) /* the first t3 may be equal t0 ... optimize? */
addiu a1, a1, 4
addiu a0, a0, 4
bne a0, a3, $wordCopy_loop
sw t3, -4(a0)
/* For the last (<8) bytes */
$last8:
blez a2, leave
addu a3, a0, a2 /* a3 is the last dst address */
$last8loop:
lb v1, 0(a1)
addiu a1, a1, 1
addiu a0, a0, 1
bne a0, a3, $last8loop
sb v1, -1(a0)
leave: j ra
nop
/*
* UNALIGNED case
*/
$unaligned:
/* got here with a3="negu a0" */
andi a3, a3, 0x3 /* test if the a0 is word aligned */
beqz a3, $ua_chk16w
subu a2, a2, a3 /* bytes left after initial a3 bytes */
LWHI v1, 0(a1)
LWLO v1, 3(a1)
addu a1, a1, a3 /* a3 may be here 1, 2 or 3 */
SWHI v1, 0(a0)
addu a0, a0, a3 /* below the dst will be word aligned (NOTE1) */
$ua_chk16w: andi t8, a2, 0x3f /* any whole 64-byte chunks? */
/* t8 is the byte count after 64-byte chunks */
beq a2, t8, $ua_chk8w /* if a2==t8, no 64-byte chunks */
/* There will be at most 1 32-byte chunk after it */
subu a3, a2, t8 /* subtract from a2 the reminder */
/* Here a3 counts bytes in 16w chunks */
addu a3, a0, a3 /* Now a3 is the final dst after 64-byte chunks */
addu t0, a0, a2 /* t0 is the "past the end" address */
subu t9, t0, 160 /* t9 is the "last safe pref 30, 128(a0)" address */
pref 0, 0(a1) /* bring the first line of src, addr 0 */
pref 0, 32(a1) /* bring the second line of src, addr 32 */
pref 0, 64(a1) /* bring the third line of src, addr 64 */
pref 30, 32(a0) /* safe, as we have at least 64 bytes ahead */
/* In case the a0 > t9 don't use "pref 30" at all */
sgtu v1, a0, t9
bgtz v1, $ua_loop16w /* skip "pref 30, 64(a0)" for too short arrays */
nop
/* otherwise, start with using pref30 */
pref 30, 64(a0)
$ua_loop16w:
pref 0, 96(a1)
LWHI t0, 0(a1)
LWLO t0, 3(a1)
LWHI t1, 4(a1)
bgtz v1, $ua_skip_pref30_96
LWLO t1, 7(a1)
pref 30, 96(a0) /* continue setting up the dest, addr 96 */
$ua_skip_pref30_96:
LWHI t2, 8(a1)
LWLO t2, 11(a1)
LWHI t3, 12(a1)
LWLO t3, 15(a1)
LWHI t4, 16(a1)
LWLO t4, 19(a1)
LWHI t5, 20(a1)
LWLO t5, 23(a1)
LWHI t6, 24(a1)
LWLO t6, 27(a1)
LWHI t7, 28(a1)
LWLO t7, 31(a1)
pref 0, 128(a1) /* bring the next lines of src, addr 128 */
sw t0, 0(a0)
sw t1, 4(a0)
sw t2, 8(a0)
sw t3, 12(a0)
sw t4, 16(a0)
sw t5, 20(a0)
sw t6, 24(a0)
sw t7, 28(a0)
LWHI t0, 32(a1)
LWLO t0, 35(a1)
LWHI t1, 36(a1)
bgtz v1, $ua_skip_pref30_128
LWLO t1, 39(a1)
pref 30, 128(a0) /* continue setting up the dest, addr 128 */
$ua_skip_pref30_128:
LWHI t2, 40(a1)
LWLO t2, 43(a1)
LWHI t3, 44(a1)
LWLO t3, 47(a1)
LWHI t4, 48(a1)
LWLO t4, 51(a1)
LWHI t5, 52(a1)
LWLO t5, 55(a1)
LWHI t6, 56(a1)
LWLO t6, 59(a1)
LWHI t7, 60(a1)
LWLO t7, 63(a1)
pref 0, 160(a1) /* bring the next lines of src, addr 160 */
sw t0, 32(a0)
sw t1, 36(a0)
sw t2, 40(a0)
sw t3, 44(a0)
sw t4, 48(a0)
sw t5, 52(a0)
sw t6, 56(a0)
sw t7, 60(a0)
addiu a0, a0, 64 /* adding 64 to dest */
sgtu v1, a0, t9
bne a0, a3, $ua_loop16w
addiu a1, a1, 64 /* adding 64 to src */
move a2, t8
/* Here we have src and dest word-aligned but less than 64-bytes to go */
$ua_chk8w:
pref 0, 0x0(a1)
andi t8, a2, 0x1f /* is there a 32-byte chunk? */
/* the t8 is the reminder count */
beq a2, t8, $ua_chk1w /* when a2=t8, no 32-byte chunk */
LWHI t0, 0(a1)
LWLO t0, 3(a1)
LWHI t1, 4(a1)
LWLO t1, 7(a1)
LWHI t2, 8(a1)
LWLO t2, 11(a1)
LWHI t3, 12(a1)
LWLO t3, 15(a1)
LWHI t4, 16(a1)
LWLO t4, 19(a1)
LWHI t5, 20(a1)
LWLO t5, 23(a1)
LWHI t6, 24(a1)
LWLO t6, 27(a1)
LWHI t7, 28(a1)
LWLO t7, 31(a1)
addiu a1, a1, 32
sw t0, 0(a0)
sw t1, 4(a0)
sw t2, 8(a0)
sw t3, 12(a0)
sw t4, 16(a0)
sw t5, 20(a0)
sw t6, 24(a0)
sw t7, 28(a0)
addiu a0, a0, 32
$ua_chk1w:
andi a2, t8, 0x3 /* now a2 is the reminder past 1w chunks */
beq a2, t8, $ua_smallCopy
subu a3, t8, a2 /* a3 is count of bytes in 1w chunks */
addu a3, a0, a3 /* now a3 is the dst address past the 1w chunks */
/* copying in words (4-byte chunks) */
$ua_wordCopy_loop:
LWHI v1, 0(a1)
LWLO v1, 3(a1)
addiu a1, a1, 4
addiu a0, a0, 4 /* note: dst=a0 is word aligned here, see NOTE1 */
bne a0, a3, $ua_wordCopy_loop
sw v1, -4(a0)
/* Now less than 4 bytes (value in a2) left to copy */
$ua_smallCopy:
beqz a2, leave
addu a3, a0, a2 /* a3 is the last dst address */
$ua_smallCopy_loop:
lb v1, 0(a1)
addiu a1, a1, 1
addiu a0, a0, 1
bne a0, a3, $ua_smallCopy_loop
sb v1, -1(a0)
j ra
nop
END(pixman_mips_fast_memcpy)

View file

@ -0,0 +1,94 @@
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
*
* 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 SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* 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 "pixman-private.h"
#if defined(USE_MIPS_DSPR2) || defined(USE_LOONGSON_MMI)
#include <string.h>
#include <stdlib.h>
static pixman_bool_t
have_feature (const char *search_string)
{
#if defined (__linux__) /* linux ELF */
/* Simple detection of MIPS features at runtime for Linux.
* It is based on /proc/cpuinfo, which reveals hardware configuration
* to user-space applications. According to MIPS (early 2010), no similar
* facility is universally available on the MIPS architectures, so it's up
* to individual OSes to provide such.
*/
const char *file_name = "/proc/cpuinfo";
char cpuinfo_line[256];
FILE *f = NULL;
if ((f = fopen (file_name, "r")) == NULL)
return FALSE;
while (fgets (cpuinfo_line, sizeof (cpuinfo_line), f) != NULL)
{
if (strstr (cpuinfo_line, search_string) != NULL)
{
fclose (f);
return TRUE;
}
}
fclose (f);
#endif
/* Did not find string in the proc file, or not Linux ELF. */
return FALSE;
}
#endif
pixman_implementation_t *
_pixman_mips_get_implementations (pixman_implementation_t *imp)
{
#ifdef USE_LOONGSON_MMI
/* I really don't know if some Loongson CPUs don't have MMI. */
if (!_pixman_disabled ("loongson-mmi") && have_feature ("Loongson"))
imp = _pixman_implementation_create_mmx (imp);
#endif
#ifdef USE_MIPS_DSPR2
if (!_pixman_disabled ("mips-dspr2"))
{
int already_compiling_everything_for_dspr2 = 0;
#if defined(__mips_dsp) && (__mips_dsp_rev >= 2)
already_compiling_everything_for_dspr2 = 1;
#endif
if (already_compiling_everything_for_dspr2 ||
/* Only currently available MIPS core that supports DSPr2 is 74K. */
have_feature ("MIPS 74K"))
{
imp = _pixman_implementation_create_mips_dspr2 (imp);
}
}
#endif
return imp;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,176 @@
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
/*
* Copyright © 2011 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include "pixman-private.h"
#include "pixman-combine32.h"
#include "pixman-inlines.h"
static void
noop_composite (pixman_implementation_t *imp,
pixman_composite_info_t *info)
{
return;
}
static void
dest_write_back_direct (pixman_iter_t *iter)
{
iter->buffer += iter->image->bits.rowstride;
}
static uint32_t *
noop_get_scanline (pixman_iter_t *iter, const uint32_t *mask)
{
uint32_t *result = iter->buffer;
iter->buffer += iter->image->bits.rowstride;
return result;
}
static uint32_t *
get_scanline_null (pixman_iter_t *iter, const uint32_t *mask)
{
return NULL;
}
static pixman_bool_t
noop_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
{
pixman_image_t *image = iter->image;
#define FLAGS \
(FAST_PATH_STANDARD_FLAGS | FAST_PATH_ID_TRANSFORM)
if (!image)
{
iter->get_scanline = get_scanline_null;
}
else if ((iter->iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) ==
(ITER_IGNORE_ALPHA | ITER_IGNORE_RGB))
{
iter->get_scanline = _pixman_iter_get_scanline_noop;
}
else if (image->common.extended_format_code == PIXMAN_solid &&
(iter->image->type == SOLID ||
(iter->image_flags & FAST_PATH_NO_ALPHA_MAP)))
{
if (iter->iter_flags & ITER_NARROW)
{
uint32_t *buffer = iter->buffer;
uint32_t *end = buffer + iter->width;
uint32_t color;
if (image->type == SOLID)
color = image->solid.color_32;
else
color = image->bits.fetch_pixel_32 (&image->bits, 0, 0);
while (buffer < end)
*(buffer++) = color;
}
else
{
argb_t *buffer = (argb_t *)iter->buffer;
argb_t *end = buffer + iter->width;
argb_t color;
if (image->type == SOLID)
color = image->solid.color_float;
else
color = image->bits.fetch_pixel_float (&image->bits, 0, 0);
while (buffer < end)
*(buffer++) = color;
}
iter->get_scanline = _pixman_iter_get_scanline_noop;
}
else if (image->common.extended_format_code == PIXMAN_a8r8g8b8 &&
(iter->iter_flags & ITER_NARROW) &&
(iter->image_flags & FLAGS) == FLAGS &&
iter->x >= 0 && iter->y >= 0 &&
iter->x + iter->width <= image->bits.width &&
iter->y + iter->height <= image->bits.height)
{
iter->buffer =
image->bits.bits + iter->y * image->bits.rowstride + iter->x;
iter->get_scanline = noop_get_scanline;
}
else
{
return FALSE;
}
return TRUE;
}
static pixman_bool_t
noop_dest_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter)
{
pixman_image_t *image = iter->image;
uint32_t image_flags = iter->image_flags;
uint32_t iter_flags = iter->iter_flags;
if ((image_flags & FAST_PATH_STD_DEST_FLAGS) == FAST_PATH_STD_DEST_FLAGS &&
(iter_flags & ITER_NARROW) == ITER_NARROW &&
((image->common.extended_format_code == PIXMAN_a8r8g8b8) ||
(image->common.extended_format_code == PIXMAN_x8r8g8b8 &&
(iter_flags & (ITER_LOCALIZED_ALPHA)))))
{
iter->buffer = image->bits.bits + iter->y * image->bits.rowstride + iter->x;
iter->get_scanline = _pixman_iter_get_scanline_noop;
iter->write_back = dest_write_back_direct;
return TRUE;
}
else
{
return FALSE;
}
}
static const pixman_fast_path_t noop_fast_paths[] =
{
{ PIXMAN_OP_DST, PIXMAN_any, 0, PIXMAN_any, 0, PIXMAN_any, 0, noop_composite },
{ PIXMAN_OP_NONE },
};
pixman_implementation_t *
_pixman_implementation_create_noop (pixman_implementation_t *fallback)
{
pixman_implementation_t *imp =
_pixman_implementation_create (fallback, noop_fast_paths);
imp->src_iter_init = noop_src_iter_init;
imp->dest_iter_init = noop_dest_iter_init;
return imp;
}

View file

@ -0,0 +1,155 @@
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
*
* 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 SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* 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 "pixman-private.h"
#ifdef USE_VMX
/* The CPU detection code needs to be in a file not compiled with
* "-maltivec -mabi=altivec", as gcc would try to save vector register
* across function calls causing SIGILL on cpus without Altivec/vmx.
*/
#ifdef __APPLE__
#include <sys/sysctl.h>
static pixman_bool_t
pixman_have_vmx (void)
{
int error, have_vmx;
size_t length = sizeof(have_vmx);
error = sysctlbyname ("hw.optional.altivec", &have_vmx, &length, NULL, 0);
if (error)
return FALSE;
return have_vmx;
}
#elif defined (__OpenBSD__)
#include <sys/param.h>
#include <sys/sysctl.h>
#include <machine/cpu.h>
static pixman_bool_t
pixman_have_vmx (void)
{
int error, have_vmx;
int mib[2] = { CTL_MACHDEP, CPU_ALTIVEC };
size_t length = sizeof(have_vmx);
error = sysctl (mib, 2, &have_vmx, &length, NULL, 0);
if (error != 0)
return FALSE;
return have_vmx;
}
#elif defined (__linux__)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <linux/auxvec.h>
#include <asm/cputable.h>
static pixman_bool_t
pixman_have_vmx (void)
{
int have_vmx = FALSE;
int fd;
struct
{
unsigned long type;
unsigned long value;
} aux;
fd = open ("/proc/self/auxv", O_RDONLY);
if (fd >= 0)
{
while (read (fd, &aux, sizeof (aux)) == sizeof (aux))
{
if (aux.type == AT_HWCAP && (aux.value & PPC_FEATURE_HAS_ALTIVEC))
{
have_vmx = TRUE;
break;
}
}
close (fd);
}
return have_vmx;
}
#else /* !__APPLE__ && !__OpenBSD__ && !__linux__ */
#include <signal.h>
#include <setjmp.h>
static jmp_buf jump_env;
static void
vmx_test (int sig,
siginfo_t *si,
void * unused)
{
longjmp (jump_env, 1);
}
static pixman_bool_t
pixman_have_vmx (void)
{
struct sigaction sa, osa;
int jmp_result;
sa.sa_flags = SA_SIGINFO;
sigemptyset (&sa.sa_mask);
sa.sa_sigaction = vmx_test;
sigaction (SIGILL, &sa, &osa);
jmp_result = setjmp (jump_env);
if (jmp_result == 0)
{
asm volatile ( "vor 0, 0, 0" );
}
sigaction (SIGILL, &osa, NULL);
return (jmp_result == 0);
}
#endif /* __APPLE__ */
#endif /* USE_VMX */
pixman_implementation_t *
_pixman_ppc_get_implementations (pixman_implementation_t *imp)
{
#ifdef USE_VMX
if (!_pixman_disabled ("vmx") && pixman_have_vmx ())
imp = _pixman_implementation_create_vmx (imp);
#endif
return imp;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,727 @@
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
/*
*
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
* Copyright © 2000 SuSE, Inc.
* 2005 Lars Knoll & Zack Rusin, Trolltech
* Copyright © 2007 Red Hat, Inc.
*
*
* 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 Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard 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 <math.h>
#include "pixman-private.h"
#include "pixman-dither.h"
static inline pixman_fixed_32_32_t
dot (pixman_fixed_48_16_t x1,
pixman_fixed_48_16_t y1,
pixman_fixed_48_16_t z1,
pixman_fixed_48_16_t x2,
pixman_fixed_48_16_t y2,
pixman_fixed_48_16_t z2)
{
/*
* Exact computation, assuming that the input values can
* be represented as pixman_fixed_16_16_t
*/
return x1 * x2 + y1 * y2 + z1 * z2;
}
static inline double
fdot (double x1,
double y1,
double z1,
double x2,
double y2,
double z2)
{
/*
* Error can be unbound in some special cases.
* Using clever dot product algorithms (for example compensated
* dot product) would improve this but make the code much less
* obvious
*/
return x1 * x2 + y1 * y2 + z1 * z2;
}
static uint32_t
radial_compute_color (double a,
double b,
double c,
double inva,
double dr,
double mindr,
pixman_gradient_walker_t *walker,
pixman_repeat_t repeat)
{
/*
* In this function error propagation can lead to bad results:
* - discr can have an unbound error (if b*b-a*c is very small),
* potentially making it the opposite sign of what it should have been
* (thus clearing a pixel that would have been colored or vice-versa)
* or propagating the error to sqrtdiscr;
* if discr has the wrong sign or b is very small, this can lead to bad
* results
*
* - the algorithm used to compute the solutions of the quadratic
* equation is not numerically stable (but saves one division compared
* to the numerically stable one);
* this can be a problem if a*c is much smaller than b*b
*
* - the above problems are worse if a is small (as inva becomes bigger)
*/
double discr;
if (a == 0)
{
double t;
if (b == 0)
return 0;
t = pixman_fixed_1 / 2 * c / b;
if (repeat == PIXMAN_REPEAT_NONE)
{
if (0 <= t && t <= pixman_fixed_1)
return _pixman_gradient_walker_pixel (walker, t);
}
else
{
if (t * dr >= mindr)
return _pixman_gradient_walker_pixel (walker, t);
}
return 0;
}
discr = fdot (b, a, 0, b, -c, 0);
if (discr >= 0)
{
double sqrtdiscr, t0, t1;
sqrtdiscr = sqrt (discr);
t0 = (b + sqrtdiscr) * inva;
t1 = (b - sqrtdiscr) * inva;
/*
* The root that must be used is the biggest one that belongs
* to the valid range ([0,1] for PIXMAN_REPEAT_NONE, any
* solution that results in a positive radius otherwise).
*
* If a > 0, t0 is the biggest solution, so if it is valid, it
* is the correct result.
*
* If a < 0, only one of the solutions can be valid, so the
* order in which they are tested is not important.
*/
if (repeat == PIXMAN_REPEAT_NONE)
{
if (0 <= t0 && t0 <= pixman_fixed_1)
return _pixman_gradient_walker_pixel (walker, t0);
else if (0 <= t1 && t1 <= pixman_fixed_1)
return _pixman_gradient_walker_pixel (walker, t1);
}
else
{
if (t0 * dr >= mindr)
return _pixman_gradient_walker_pixel (walker, t0);
else if (t1 * dr >= mindr)
return _pixman_gradient_walker_pixel (walker, t1);
}
}
return 0;
}
static uint32_t *
radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
{
/*
* Implementation of radial gradients following the PDF specification.
* See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
* Manual (PDF 32000-1:2008 at the time of this writing).
*
* In the radial gradient problem we are given two circles (c₁,r₁) and
* (c₂,r₂) that define the gradient itself.
*
* Mathematically the gradient can be defined as the family of circles
*
* ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
*
* excluding those circles whose radius would be < 0. When a point
* belongs to more than one circle, the one with a bigger t is the only
* one that contributes to its color. When a point does not belong
* to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
* Further limitations on the range of values for t are imposed when
* the gradient is not repeated, namely t must belong to [0,1].
*
* The graphical result is the same as drawing the valid (radius > 0)
* circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient
* is not repeated) using SOURCE operator composition.
*
* It looks like a cone pointing towards the viewer if the ending circle
* is smaller than the starting one, a cone pointing inside the page if
* the starting circle is the smaller one and like a cylinder if they
* have the same radius.
*
* What we actually do is, given the point whose color we are interested
* in, compute the t values for that point, solving for t in:
*
* length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
*
* Let's rewrite it in a simpler way, by defining some auxiliary
* variables:
*
* cd = c₂ - c₁
* pd = p - c₁
* dr = r₂ - r₁
* length(t·cd - pd) = r₁ + t·dr
*
* which actually means
*
* hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
*
* or
*
* ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
*
* If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
*
* (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
*
* where we can actually expand the squares and solve for t:
*
* t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
* = r₁² + 2·r₁·t·dr + t²·dr²
*
* (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
* (pdx² + pdy² - r₁²) = 0
*
* A = cdx² + cdy² - dr²
* B = pdx·cdx + pdy·cdy + r₁·dr
* C = pdx² + pdy² - r₁²
* At² - 2Bt + C = 0
*
* The solutions (unless the equation degenerates because of A = 0) are:
*
* t = (B ± ⎷(B² - A·C)) / A
*
* The solution we are going to prefer is the bigger one, unless the
* radius associated to it is negative (or it falls outside the valid t
* range).
*
* Additional observations (useful for optimizations):
* A does not depend on p
*
* A < 0 <=> one of the two circles completely contains the other one
* <=> for every p, the radiuses associated with the two t solutions
* have opposite sign
*/
pixman_image_t *image = iter->image;
int x = iter->x;
int y = iter->y;
int width = iter->width;
uint32_t *buffer = iter->buffer;
gradient_t *gradient = (gradient_t *)image;
radial_gradient_t *radial = (radial_gradient_t *)image;
uint32_t *end = buffer + width;
pixman_gradient_walker_t walker;
pixman_vector_t v, unit;
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
_pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
if (image->common.transform)
{
if (!pixman_transform_point_3d (image->common.transform, &v))
return iter->buffer;
unit.vector[0] = image->common.transform->matrix[0][0];
unit.vector[1] = image->common.transform->matrix[1][0];
unit.vector[2] = image->common.transform->matrix[2][0];
}
else
{
unit.vector[0] = pixman_fixed_1;
unit.vector[1] = 0;
unit.vector[2] = 0;
}
if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)
{
/*
* Given:
*
* t = (B ± ⎷(B² - A·C)) / A
*
* where
*
* A = cdx² + cdy² - dr²
* B = pdx·cdx + pdy·cdy + r₁·dr
* C = pdx² + pdy² - r₁²
* det = B² - A·C
*
* Since we have an affine transformation, we know that (pdx, pdy)
* increase linearly with each pixel,
*
* pdx = pdx₀ + n·ux,
* pdy = pdy₀ + n·uy,
*
* we can then express B, C and det through multiple differentiation.
*/
pixman_fixed_32_32_t b, db, c, dc, ddc;
/* warning: this computation may overflow */
v.vector[0] -= radial->c1.x;
v.vector[1] -= radial->c1.y;
/*
* B and C are computed and updated exactly.
* If fdot was used instead of dot, in the worst case it would
* lose 11 bits of precision in each of the multiplication and
* summing up would zero out all the bit that were preserved,
* thus making the result 0 instead of the correct one.
* This would mean a worst case of unbound relative error or
* about 2^10 absolute error
*/
b = dot (v.vector[0], v.vector[1], radial->c1.radius,
radial->delta.x, radial->delta.y, radial->delta.radius);
db = dot (unit.vector[0], unit.vector[1], 0,
radial->delta.x, radial->delta.y, 0);
c = dot (v.vector[0], v.vector[1],
-((pixman_fixed_48_16_t) radial->c1.radius),
v.vector[0], v.vector[1], radial->c1.radius);
dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0],
2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1],
0,
unit.vector[0], unit.vector[1], 0);
ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
unit.vector[0], unit.vector[1], 0);
while (buffer < end)
{
if (!mask || *mask++)
{
*buffer = radial_compute_color (radial->a, b, c,
radial->inva,
radial->delta.radius,
radial->mindr,
&walker,
image->common.repeat);
}
b += db;
c += dc;
dc += ddc;
++buffer;
}
}
else
{
/* projective */
/* Warning:
* error propagation guarantees are much looser than in the affine case
*/
while (buffer < end)
{
if (!mask || *mask++)
{
if (v.vector[2] != 0)
{
double pdx, pdy, invv2, b, c;
invv2 = 1. * pixman_fixed_1 / v.vector[2];
pdx = v.vector[0] * invv2 - radial->c1.x;
/* / pixman_fixed_1 */
pdy = v.vector[1] * invv2 - radial->c1.y;
/* / pixman_fixed_1 */
b = fdot (pdx, pdy, radial->c1.radius,
radial->delta.x, radial->delta.y,
radial->delta.radius);
/* / pixman_fixed_1 / pixman_fixed_1 */
c = fdot (pdx, pdy, -radial->c1.radius,
pdx, pdy, radial->c1.radius);
/* / pixman_fixed_1 / pixman_fixed_1 */
*buffer = radial_compute_color (radial->a, b, c,
radial->inva,
radial->delta.radius,
radial->mindr,
&walker,
image->common.repeat);
}
else
{
*buffer = 0;
}
}
++buffer;
v.vector[0] += unit.vector[0];
v.vector[1] += unit.vector[1];
v.vector[2] += unit.vector[2];
}
}
iter->y++;
return iter->buffer;
}
static uint32_t *
radial_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask)
{
/*
* Implementation of radial gradients following the PDF specification.
* See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
* Manual (PDF 32000-1:2008 at the time of this writing).
*
* In the radial gradient problem we are given two circles (c₁,r₁) and
* (c₂,r₂) that define the gradient itself.
*
* Mathematically the gradient can be defined as the family of circles
*
* ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
*
* excluding those circles whose radius would be < 0. When a point
* belongs to more than one circle, the one with a bigger t is the only
* one that contributes to its color. When a point does not belong
* to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
* Further limitations on the range of values for t are imposed when
* the gradient is not repeated, namely t must belong to [0,1].
*
* The graphical result is the same as drawing the valid (radius > 0)
* circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient
* is not repeated) using SOURCE operator composition.
*
* It looks like a cone pointing towards the viewer if the ending circle
* is smaller than the starting one, a cone pointing inside the page if
* the starting circle is the smaller one and like a cylinder if they
* have the same radius.
*
* What we actually do is, given the point whose color we are interested
* in, compute the t values for that point, solving for t in:
*
* length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
*
* Let's rewrite it in a simpler way, by defining some auxiliary
* variables:
*
* cd = c₂ - c₁
* pd = p - c₁
* dr = r₂ - r₁
* length(t·cd - pd) = r₁ + t·dr
*
* which actually means
*
* hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
*
* or
*
* ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
*
* If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
*
* (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
*
* where we can actually expand the squares and solve for t:
*
* t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
* = r₁² + 2·r₁·t·dr + t²·dr²
*
* (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
* (pdx² + pdy² - r₁²) = 0
*
* A = cdx² + cdy² - dr²
* B = pdx·cdx + pdy·cdy + r₁·dr
* C = pdx² + pdy² - r₁²
* At² - 2Bt + C = 0
*
* The solutions (unless the equation degenerates because of A = 0) are:
*
* t = (B ± ⎷(B² - A·C)) / A
*
* The solution we are going to prefer is the bigger one, unless the
* radius associated to it is negative (or it falls outside the valid t
* range).
*
* Additional observations (useful for optimizations):
* A does not depend on p
*
* A < 0 <=> one of the two circles completely contains the other one
* <=> for every p, the radiuses associated with the two t solutions
* have opposite sign
*/
pixman_image_t *image = iter->image;
int x = iter->x;
int y = iter->y;
int width = iter->width;
uint16_t *buffer = iter->buffer;
pixman_bool_t toggle = ((x ^ y) & 1);
gradient_t *gradient = (gradient_t *)image;
radial_gradient_t *radial = (radial_gradient_t *)image;
uint16_t *end = buffer + width;
pixman_gradient_walker_t walker;
pixman_vector_t v, unit;
/* reference point is the center of the pixel */
v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
v.vector[2] = pixman_fixed_1;
_pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
if (image->common.transform)
{
if (!pixman_transform_point_3d (image->common.transform, &v))
return iter->buffer;
unit.vector[0] = image->common.transform->matrix[0][0];
unit.vector[1] = image->common.transform->matrix[1][0];
unit.vector[2] = image->common.transform->matrix[2][0];
}
else
{
unit.vector[0] = pixman_fixed_1;
unit.vector[1] = 0;
unit.vector[2] = 0;
}
if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)
{
/*
* Given:
*
* t = (B ± ⎷(B² - A·C)) / A
*
* where
*
* A = cdx² + cdy² - dr²
* B = pdx·cdx + pdy·cdy + r₁·dr
* C = pdx² + pdy² - r₁²
* det = B² - A·C
*
* Since we have an affine transformation, we know that (pdx, pdy)
* increase linearly with each pixel,
*
* pdx = pdx₀ + n·ux,
* pdy = pdy₀ + n·uy,
*
* we can then express B, C and det through multiple differentiation.
*/
pixman_fixed_32_32_t b, db, c, dc, ddc;
/* warning: this computation may overflow */
v.vector[0] -= radial->c1.x;
v.vector[1] -= radial->c1.y;
/*
* B and C are computed and updated exactly.
* If fdot was used instead of dot, in the worst case it would
* lose 11 bits of precision in each of the multiplication and
* summing up would zero out all the bit that were preserved,
* thus making the result 0 instead of the correct one.
* This would mean a worst case of unbound relative error or
* about 2^10 absolute error
*/
b = dot (v.vector[0], v.vector[1], radial->c1.radius,
radial->delta.x, radial->delta.y, radial->delta.radius);
db = dot (unit.vector[0], unit.vector[1], 0,
radial->delta.x, radial->delta.y, 0);
c = dot (v.vector[0], v.vector[1],
-((pixman_fixed_48_16_t) radial->c1.radius),
v.vector[0], v.vector[1], radial->c1.radius);
dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0],
2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1],
0,
unit.vector[0], unit.vector[1], 0);
ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
unit.vector[0], unit.vector[1], 0);
while (buffer < end)
{
if (!mask || *mask++)
{
*buffer = dither_8888_to_0565(
radial_compute_color (radial->a, b, c,
radial->inva,
radial->delta.radius,
radial->mindr,
&walker,
image->common.repeat),
toggle);
}
toggle ^= 1;
b += db;
c += dc;
dc += ddc;
++buffer;
}
}
else
{
/* projective */
/* Warning:
* error propagation guarantees are much looser than in the affine case
*/
while (buffer < end)
{
if (!mask || *mask++)
{
if (v.vector[2] != 0)
{
double pdx, pdy, invv2, b, c;
invv2 = 1. * pixman_fixed_1 / v.vector[2];
pdx = v.vector[0] * invv2 - radial->c1.x;
/* / pixman_fixed_1 */
pdy = v.vector[1] * invv2 - radial->c1.y;
/* / pixman_fixed_1 */
b = fdot (pdx, pdy, radial->c1.radius,
radial->delta.x, radial->delta.y,
radial->delta.radius);
/* / pixman_fixed_1 / pixman_fixed_1 */
c = fdot (pdx, pdy, -radial->c1.radius,
pdx, pdy, radial->c1.radius);
/* / pixman_fixed_1 / pixman_fixed_1 */
*buffer = dither_8888_to_0565 (
radial_compute_color (radial->a, b, c,
radial->inva,
radial->delta.radius,
radial->mindr,
&walker,
image->common.repeat),
toggle);
}
else
{
*buffer = 0;
}
}
++buffer;
toggle ^= 1;
v.vector[0] += unit.vector[0];
v.vector[1] += unit.vector[1];
v.vector[2] += unit.vector[2];
}
}
iter->y++;
return iter->buffer;
}
static uint32_t *
radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
{
uint32_t *buffer = radial_get_scanline_narrow (iter, NULL);
pixman_expand_to_float (
(argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
return buffer;
}
void
_pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
{
if (iter->iter_flags & ITER_16)
iter->get_scanline = radial_get_scanline_16;
else if (iter->iter_flags & ITER_NARROW)
iter->get_scanline = radial_get_scanline_narrow;
else
iter->get_scanline = radial_get_scanline_wide;
}
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_radial_gradient (const pixman_point_fixed_t * inner,
const pixman_point_fixed_t * outer,
pixman_fixed_t inner_radius,
pixman_fixed_t outer_radius,
const pixman_gradient_stop_t *stops,
int n_stops)
{
pixman_image_t *image;
radial_gradient_t *radial;
image = _pixman_image_allocate ();
if (!image)
return NULL;
radial = &image->radial;
if (!_pixman_init_gradient (&radial->common, stops, n_stops))
{
free (image);
return NULL;
}
image->type = RADIAL;
radial->c1.x = inner->x;
radial->c1.y = inner->y;
radial->c1.radius = inner_radius;
radial->c2.x = outer->x;
radial->c2.y = outer->y;
radial->c2.radius = outer_radius;
/* warning: this computations may overflow */
radial->delta.x = radial->c2.x - radial->c1.x;
radial->delta.y = radial->c2.y - radial->c1.y;
radial->delta.radius = radial->c2.radius - radial->c1.radius;
/* computed exactly, then cast to double -> every bit of the double
representation is correct (53 bits) */
radial->a = dot (radial->delta.x, radial->delta.y, -radial->delta.radius,
radial->delta.x, radial->delta.y, radial->delta.radius);
if (radial->a != 0)
radial->inva = 1. * pixman_fixed_1 / radial->a;
radial->mindr = -1. * pixman_fixed_1 * radial->c1.radius;
return image;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,67 @@
/*
* Copyright © 2008 Red Hat, Inc.
*
* 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, Inc. not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Red Hat, Inc. makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL RED HAT, INC. 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.
*
* Author: Soren Sandmann <sandmann@redhat.com>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#undef PIXMAN_DISABLE_DEPRECATED
#include "pixman-private.h"
#include <stdlib.h>
typedef pixman_box16_t box_type_t;
typedef pixman_region16_data_t region_data_type_t;
typedef pixman_region16_t region_type_t;
typedef int32_t overflow_int_t;
typedef struct {
int x, y;
} point_type_t;
#define PREFIX(x) pixman_region##x
#define PIXMAN_REGION_MAX INT16_MAX
#define PIXMAN_REGION_MIN INT16_MIN
#include "pixman-region.c"
/* This function exists only to make it possible to preserve the X ABI -
* it should go away at first opportunity.
*
* The problem is that the X ABI exports the three structs and has used
* them through macros. So the X server calls this function with
* the addresses of those structs which makes the existing code continue to
* work.
*/
PIXMAN_EXPORT void
pixman_region_set_static_pointers (pixman_box16_t *empty_box,
pixman_region16_data_t *empty_data,
pixman_region16_data_t *broken_data)
{
pixman_region_empty_box = empty_box;
pixman_region_empty_data = empty_data;
pixman_broken_data = broken_data;
}

View file

@ -0,0 +1,47 @@
/*
* Copyright © 2008 Red Hat, Inc.
*
* 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, Inc. not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Red Hat, Inc. makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL RED HAT, INC. 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.
*
* Author: Soren Sandmann <sandmann@redhat.com>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "pixman-private.h"
#include <stdlib.h>
typedef pixman_box32_t box_type_t;
typedef pixman_region32_data_t region_data_type_t;
typedef pixman_region32_t region_type_t;
typedef int64_t overflow_int_t;
typedef struct {
int x, y;
} point_type_t;
#define PREFIX(x) pixman_region32##x
#define PIXMAN_REGION_MAX INT32_MAX
#define PIXMAN_REGION_MIN INT32_MIN
#include "pixman-region.c"

View file

@ -0,0 +1,67 @@
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007, 2009 Red Hat, Inc.
* Copyright © 2009 Soren Sandmann
*
* 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 SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* 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 "pixman-private.h"
static uint32_t
color_to_uint32 (const pixman_color_t *color)
{
return
(color->alpha >> 8 << 24) |
(color->red >> 8 << 16) |
(color->green & 0xff00) |
(color->blue >> 8);
}
static argb_t
color_to_float (const pixman_color_t *color)
{
argb_t result;
result.a = pixman_unorm_to_float (color->alpha, 16);
result.r = pixman_unorm_to_float (color->red, 16);
result.g = pixman_unorm_to_float (color->green, 16);
result.b = pixman_unorm_to_float (color->blue, 16);
return result;
}
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_solid_fill (const pixman_color_t *color)
{
pixman_image_t *img = _pixman_image_allocate ();
if (!img)
return NULL;
img->type = SOLID;
img->solid.color = *color;
img->solid.color_32 = color_to_uint32 (color);
img->solid.color_float = color_to_float (color);
return img;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,66 @@
/*
* Copyright © 2007 Red Hat, Inc.
*
* 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.
*
* RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
* 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 <stdio.h>
#include "pixman-private.h"
#ifdef PIXMAN_TIMERS
static pixman_timer_t *timers;
static void
dump_timers (void)
{
pixman_timer_t *timer;
for (timer = timers; timer != NULL; timer = timer->next)
{
printf ("%s: total: %llu n: %llu avg: %f\n",
timer->name,
timer->total,
timer->n_times,
timer->total / (double)timer->n_times);
}
}
void
pixman_timer_register (pixman_timer_t *timer)
{
static int initialized;
int atexit (void (*function)(void));
if (!initialized)
{
atexit (dump_timers);
initialized = 1;
}
timer->next = timers;
timers = timer;
}
#endif

View file

@ -0,0 +1,711 @@
/*
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
* Copyright © 2004 Keith Packard
*
* 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 Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD 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 <stdio.h>
#include <stdlib.h>
#include "pixman-private.h"
/*
* Compute the smallest value greater than or equal to y which is on a
* grid row.
*/
PIXMAN_EXPORT pixman_fixed_t
pixman_sample_ceil_y (pixman_fixed_t y, int n)
{
pixman_fixed_t f = pixman_fixed_frac (y);
pixman_fixed_t i = pixman_fixed_floor (y);
f = DIV (f - Y_FRAC_FIRST (n) + (STEP_Y_SMALL (n) - pixman_fixed_e), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) +
Y_FRAC_FIRST (n);
if (f > Y_FRAC_LAST (n))
{
if (pixman_fixed_to_int (i) == 0x7fff)
{
f = 0xffff; /* saturate */
}
else
{
f = Y_FRAC_FIRST (n);
i += pixman_fixed_1;
}
}
return (i | f);
}
/*
* Compute the largest value strictly less than y which is on a
* grid row.
*/
PIXMAN_EXPORT pixman_fixed_t
pixman_sample_floor_y (pixman_fixed_t y,
int n)
{
pixman_fixed_t f = pixman_fixed_frac (y);
pixman_fixed_t i = pixman_fixed_floor (y);
f = DIV (f - pixman_fixed_e - Y_FRAC_FIRST (n), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) +
Y_FRAC_FIRST (n);
if (f < Y_FRAC_FIRST (n))
{
if (pixman_fixed_to_int (i) == 0x8000)
{
f = 0; /* saturate */
}
else
{
f = Y_FRAC_LAST (n);
i -= pixman_fixed_1;
}
}
return (i | f);
}
/*
* Step an edge by any amount (including negative values)
*/
PIXMAN_EXPORT void
pixman_edge_step (pixman_edge_t *e,
int n)
{
pixman_fixed_48_16_t ne;
e->x += n * e->stepx;
ne = e->e + n * (pixman_fixed_48_16_t) e->dx;
if (n >= 0)
{
if (ne > 0)
{
int nx = (ne + e->dy - 1) / e->dy;
e->e = ne - nx * (pixman_fixed_48_16_t) e->dy;
e->x += nx * e->signdx;
}
}
else
{
if (ne <= -e->dy)
{
int nx = (-ne) / e->dy;
e->e = ne + nx * (pixman_fixed_48_16_t) e->dy;
e->x -= nx * e->signdx;
}
}
}
/*
* A private routine to initialize the multi-step
* elements of an edge structure
*/
static void
_pixman_edge_multi_init (pixman_edge_t * e,
int n,
pixman_fixed_t *stepx_p,
pixman_fixed_t *dx_p)
{
pixman_fixed_t stepx;
pixman_fixed_48_16_t ne;
ne = n * (pixman_fixed_48_16_t) e->dx;
stepx = n * e->stepx;
if (ne > 0)
{
int nx = ne / e->dy;
ne -= nx * (pixman_fixed_48_16_t)e->dy;
stepx += nx * e->signdx;
}
*dx_p = ne;
*stepx_p = stepx;
}
/*
* Initialize one edge structure given the line endpoints and a
* starting y value
*/
PIXMAN_EXPORT void
pixman_edge_init (pixman_edge_t *e,
int n,
pixman_fixed_t y_start,
pixman_fixed_t x_top,
pixman_fixed_t y_top,
pixman_fixed_t x_bot,
pixman_fixed_t y_bot)
{
pixman_fixed_t dx, dy;
e->x = x_top;
e->e = 0;
dx = x_bot - x_top;
dy = y_bot - y_top;
e->dy = dy;
e->dx = 0;
if (dy)
{
if (dx >= 0)
{
e->signdx = 1;
e->stepx = dx / dy;
e->dx = dx % dy;
e->e = -dy;
}
else
{
e->signdx = -1;
e->stepx = -(-dx / dy);
e->dx = -dx % dy;
e->e = 0;
}
_pixman_edge_multi_init (e, STEP_Y_SMALL (n),
&e->stepx_small, &e->dx_small);
_pixman_edge_multi_init (e, STEP_Y_BIG (n),
&e->stepx_big, &e->dx_big);
}
pixman_edge_step (e, y_start - y_top);
}
/*
* Initialize one edge structure given a line, starting y value
* and a pixel offset for the line
*/
PIXMAN_EXPORT void
pixman_line_fixed_edge_init (pixman_edge_t * e,
int n,
pixman_fixed_t y,
const pixman_line_fixed_t *line,
int x_off,
int y_off)
{
pixman_fixed_t x_off_fixed = pixman_int_to_fixed (x_off);
pixman_fixed_t y_off_fixed = pixman_int_to_fixed (y_off);
const pixman_point_fixed_t *top, *bot;
if (line->p1.y <= line->p2.y)
{
top = &line->p1;
bot = &line->p2;
}
else
{
top = &line->p2;
bot = &line->p1;
}
pixman_edge_init (e, n, y,
top->x + x_off_fixed,
top->y + y_off_fixed,
bot->x + x_off_fixed,
bot->y + y_off_fixed);
}
PIXMAN_EXPORT void
pixman_add_traps (pixman_image_t * image,
int16_t x_off,
int16_t y_off,
int ntrap,
const pixman_trap_t *traps)
{
int bpp;
int height;
pixman_fixed_t x_off_fixed;
pixman_fixed_t y_off_fixed;
pixman_edge_t l, r;
pixman_fixed_t t, b;
_pixman_image_validate (image);
height = image->bits.height;
bpp = PIXMAN_FORMAT_BPP (image->bits.format);
x_off_fixed = pixman_int_to_fixed (x_off);
y_off_fixed = pixman_int_to_fixed (y_off);
while (ntrap--)
{
t = traps->top.y + y_off_fixed;
if (t < 0)
t = 0;
t = pixman_sample_ceil_y (t, bpp);
b = traps->bot.y + y_off_fixed;
if (pixman_fixed_to_int (b) >= height)
b = pixman_int_to_fixed (height) - 1;
b = pixman_sample_floor_y (b, bpp);
if (b >= t)
{
/* initialize edge walkers */
pixman_edge_init (&l, bpp, t,
traps->top.l + x_off_fixed,
traps->top.y + y_off_fixed,
traps->bot.l + x_off_fixed,
traps->bot.y + y_off_fixed);
pixman_edge_init (&r, bpp, t,
traps->top.r + x_off_fixed,
traps->top.y + y_off_fixed,
traps->bot.r + x_off_fixed,
traps->bot.y + y_off_fixed);
pixman_rasterize_edges (image, &l, &r, t, b);
}
traps++;
}
}
#if 0
static void
dump_image (pixman_image_t *image,
const char * title)
{
int i, j;
if (!image->type == BITS)
printf ("%s is not a regular image\n", title);
if (!image->bits.format == PIXMAN_a8)
printf ("%s is not an alpha mask\n", title);
printf ("\n\n\n%s: \n", title);
for (i = 0; i < image->bits.height; ++i)
{
uint8_t *line =
(uint8_t *)&(image->bits.bits[i * image->bits.rowstride]);
for (j = 0; j < image->bits.width; ++j)
printf ("%c", line[j] ? '#' : ' ');
printf ("\n");
}
}
#endif
PIXMAN_EXPORT void
pixman_add_trapezoids (pixman_image_t * image,
int16_t x_off,
int y_off,
int ntraps,
const pixman_trapezoid_t *traps)
{
int i;
#if 0
dump_image (image, "before");
#endif
for (i = 0; i < ntraps; ++i)
{
const pixman_trapezoid_t *trap = &(traps[i]);
if (!pixman_trapezoid_valid (trap))
continue;
pixman_rasterize_trapezoid (image, trap, x_off, y_off);
}
#if 0
dump_image (image, "after");
#endif
}
PIXMAN_EXPORT void
pixman_rasterize_trapezoid (pixman_image_t * image,
const pixman_trapezoid_t *trap,
int x_off,
int y_off)
{
int bpp;
int height;
pixman_fixed_t y_off_fixed;
pixman_edge_t l, r;
pixman_fixed_t t, b;
return_if_fail (image->type == BITS);
_pixman_image_validate (image);
if (!pixman_trapezoid_valid (trap))
return;
height = image->bits.height;
bpp = PIXMAN_FORMAT_BPP (image->bits.format);
y_off_fixed = pixman_int_to_fixed (y_off);
t = trap->top + y_off_fixed;
if (t < 0)
t = 0;
t = pixman_sample_ceil_y (t, bpp);
b = trap->bottom + y_off_fixed;
if (pixman_fixed_to_int (b) >= height)
b = pixman_int_to_fixed (height) - 1;
b = pixman_sample_floor_y (b, bpp);
if (b >= t)
{
/* initialize edge walkers */
pixman_line_fixed_edge_init (&l, bpp, t, &trap->left, x_off, y_off);
pixman_line_fixed_edge_init (&r, bpp, t, &trap->right, x_off, y_off);
pixman_rasterize_edges (image, &l, &r, t, b);
}
}
static const pixman_bool_t zero_src_has_no_effect[PIXMAN_N_OPERATORS] =
{
FALSE, /* Clear 0 0 */
FALSE, /* Src 1 0 */
TRUE, /* Dst 0 1 */
TRUE, /* Over 1 1-Aa */
TRUE, /* OverReverse 1-Ab 1 */
FALSE, /* In Ab 0 */
FALSE, /* InReverse 0 Aa */
FALSE, /* Out 1-Ab 0 */
TRUE, /* OutReverse 0 1-Aa */
TRUE, /* Atop Ab 1-Aa */
FALSE, /* AtopReverse 1-Ab Aa */
TRUE, /* Xor 1-Ab 1-Aa */
TRUE, /* Add 1 1 */
};
static pixman_bool_t
get_trap_extents (pixman_op_t op, pixman_image_t *dest,
const pixman_trapezoid_t *traps, int n_traps,
pixman_box32_t *box)
{
int i;
/* When the operator is such that a zero source has an
* effect on the underlying image, we have to
* composite across the entire destination
*/
if (!zero_src_has_no_effect [op])
{
box->x1 = 0;
box->y1 = 0;
box->x2 = dest->bits.width;
box->y2 = dest->bits.height;
return TRUE;
}
box->x1 = INT32_MAX;
box->y1 = INT32_MAX;
box->x2 = INT32_MIN;
box->y2 = INT32_MIN;
for (i = 0; i < n_traps; ++i)
{
const pixman_trapezoid_t *trap = &(traps[i]);
int y1, y2;
if (!pixman_trapezoid_valid (trap))
continue;
y1 = pixman_fixed_to_int (trap->top);
if (y1 < box->y1)
box->y1 = y1;
y2 = pixman_fixed_to_int (pixman_fixed_ceil (trap->bottom));
if (y2 > box->y2)
box->y2 = y2;
#define EXTEND_MIN(x) \
if (pixman_fixed_to_int ((x)) < box->x1) \
box->x1 = pixman_fixed_to_int ((x));
#define EXTEND_MAX(x) \
if (pixman_fixed_to_int (pixman_fixed_ceil ((x))) > box->x2) \
box->x2 = pixman_fixed_to_int (pixman_fixed_ceil ((x)));
#define EXTEND(x) \
EXTEND_MIN(x); \
EXTEND_MAX(x);
EXTEND(trap->left.p1.x);
EXTEND(trap->left.p2.x);
EXTEND(trap->right.p1.x);
EXTEND(trap->right.p2.x);
}
if (box->x1 >= box->x2 || box->y1 >= box->y2)
return FALSE;
return TRUE;
}
/*
* pixman_composite_trapezoids()
*
* All the trapezoids are conceptually rendered to an infinitely big image.
* The (0, 0) coordinates of this image are then aligned with the (x, y)
* coordinates of the source image, and then both images are aligned with
* the (x, y) coordinates of the destination. Then these three images are
* composited across the entire destination.
*/
PIXMAN_EXPORT void
pixman_composite_trapezoids (pixman_op_t op,
pixman_image_t * src,
pixman_image_t * dst,
pixman_format_code_t mask_format,
int x_src,
int y_src,
int x_dst,
int y_dst,
int n_traps,
const pixman_trapezoid_t * traps)
{
int i;
return_if_fail (PIXMAN_FORMAT_TYPE (mask_format) == PIXMAN_TYPE_A);
if (n_traps <= 0)
return;
_pixman_image_validate (src);
_pixman_image_validate (dst);
if (op == PIXMAN_OP_ADD &&
(src->common.flags & FAST_PATH_IS_OPAQUE) &&
(mask_format == dst->common.extended_format_code) &&
!(dst->common.have_clip_region))
{
for (i = 0; i < n_traps; ++i)
{
const pixman_trapezoid_t *trap = &(traps[i]);
if (!pixman_trapezoid_valid (trap))
continue;
pixman_rasterize_trapezoid (dst, trap, x_dst, y_dst);
}
}
else
{
pixman_image_t *tmp;
pixman_box32_t box;
int i;
if (!get_trap_extents (op, dst, traps, n_traps, &box))
return;
if (!(tmp = pixman_image_create_bits (
mask_format, box.x2 - box.x1, box.y2 - box.y1, NULL, -1)))
return;
for (i = 0; i < n_traps; ++i)
{
const pixman_trapezoid_t *trap = &(traps[i]);
if (!pixman_trapezoid_valid (trap))
continue;
pixman_rasterize_trapezoid (tmp, trap, - box.x1, - box.y1);
}
pixman_image_composite (op, src, tmp, dst,
x_src + box.x1, y_src + box.y1,
0, 0,
x_dst + box.x1, y_dst + box.y1,
box.x2 - box.x1, box.y2 - box.y1);
pixman_image_unref (tmp);
}
}
static int
greater_y (const pixman_point_fixed_t *a, const pixman_point_fixed_t *b)
{
if (a->y == b->y)
return a->x > b->x;
return a->y > b->y;
}
/*
* Note that the definition of this function is a bit odd because
* of the X coordinate space (y increasing downwards).
*/
static int
clockwise (const pixman_point_fixed_t *ref,
const pixman_point_fixed_t *a,
const pixman_point_fixed_t *b)
{
pixman_point_fixed_t ad, bd;
ad.x = a->x - ref->x;
ad.y = a->y - ref->y;
bd.x = b->x - ref->x;
bd.y = b->y - ref->y;
return ((pixman_fixed_32_32_t) bd.y * ad.x -
(pixman_fixed_32_32_t) ad.y * bd.x) < 0;
}
static void
triangle_to_trapezoids (const pixman_triangle_t *tri, pixman_trapezoid_t *traps)
{
const pixman_point_fixed_t *top, *left, *right, *tmp;
top = &tri->p1;
left = &tri->p2;
right = &tri->p3;
if (greater_y (top, left))
{
tmp = left;
left = top;
top = tmp;
}
if (greater_y (top, right))
{
tmp = right;
right = top;
top = tmp;
}
if (clockwise (top, right, left))
{
tmp = right;
right = left;
left = tmp;
}
/*
* Two cases:
*
* + +
* / \ / \
* / \ / \
* / + + \
* / -- -- \
* / -- -- \
* / --- --- \
* +-- --+
*/
traps->top = top->y;
traps->left.p1 = *top;
traps->left.p2 = *left;
traps->right.p1 = *top;
traps->right.p2 = *right;
if (right->y < left->y)
traps->bottom = right->y;
else
traps->bottom = left->y;
traps++;
*traps = *(traps - 1);
if (right->y < left->y)
{
traps->top = right->y;
traps->bottom = left->y;
traps->right.p1 = *right;
traps->right.p2 = *left;
}
else
{
traps->top = left->y;
traps->bottom = right->y;
traps->left.p1 = *left;
traps->left.p2 = *right;
}
}
static pixman_trapezoid_t *
convert_triangles (int n_tris, const pixman_triangle_t *tris)
{
pixman_trapezoid_t *traps;
int i;
if (n_tris <= 0)
return NULL;
traps = pixman_malloc_ab (n_tris, 2 * sizeof (pixman_trapezoid_t));
if (!traps)
return NULL;
for (i = 0; i < n_tris; ++i)
triangle_to_trapezoids (&(tris[i]), traps + 2 * i);
return traps;
}
PIXMAN_EXPORT void
pixman_composite_triangles (pixman_op_t op,
pixman_image_t * src,
pixman_image_t * dst,
pixman_format_code_t mask_format,
int x_src,
int y_src,
int x_dst,
int y_dst,
int n_tris,
const pixman_triangle_t * tris)
{
pixman_trapezoid_t *traps;
if ((traps = convert_triangles (n_tris, tris)))
{
pixman_composite_trapezoids (op, src, dst, mask_format,
x_src, y_src, x_dst, y_dst,
n_tris * 2, traps);
free (traps);
}
}
PIXMAN_EXPORT void
pixman_add_triangles (pixman_image_t *image,
int32_t x_off,
int32_t y_off,
int n_tris,
const pixman_triangle_t *tris)
{
pixman_trapezoid_t *traps;
if ((traps = convert_triangles (n_tris, tris)))
{
pixman_add_trapezoids (image, x_off, y_off,
n_tris * 2, traps);
free (traps);
}
}

View file

@ -0,0 +1,315 @@
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 1999 Keith Packard
*
* 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 SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* 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.
*
* Author: Keith Packard, SuSE, Inc.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "pixman-private.h"
pixman_bool_t
_pixman_multiply_overflows_size (size_t a, size_t b)
{
return a >= SIZE_MAX / b;
}
pixman_bool_t
_pixman_multiply_overflows_int (unsigned int a, unsigned int b)
{
return a >= INT32_MAX / b;
}
pixman_bool_t
_pixman_addition_overflows_int (unsigned int a, unsigned int b)
{
return a > INT32_MAX - b;
}
void *
pixman_malloc_ab (unsigned int a,
unsigned int b)
{
if (a >= INT32_MAX / b)
return NULL;
return malloc (a * b);
}
void *
pixman_malloc_abc (unsigned int a,
unsigned int b,
unsigned int c)
{
if (a >= INT32_MAX / b)
return NULL;
else if (a * b >= INT32_MAX / c)
return NULL;
else
return malloc (a * b * c);
}
static force_inline uint16_t
float_to_unorm (float f, int n_bits)
{
uint32_t u;
if (f > 1.0)
f = 1.0;
if (f < 0.0)
f = 0.0;
u = f * (1 << n_bits);
u -= (u >> n_bits);
return u;
}
static force_inline float
unorm_to_float (uint16_t u, int n_bits)
{
uint32_t m = ((1 << n_bits) - 1);
return (u & m) * (1.f / (float)m);
}
/*
* This function expands images from a8r8g8b8 to argb_t. To preserve
* precision, it needs to know from which source format the a8r8g8b8 pixels
* originally came.
*
* For example, if the source was PIXMAN_x1r5g5b5 and the red component
* contained bits 12345, then the 8-bit value is 12345123. To correctly
* expand this to floating point, it should be 12345 / 31.0 and not
* 12345123 / 255.0.
*/
void
pixman_expand_to_float (argb_t *dst,
const uint32_t *src,
pixman_format_code_t format,
int width)
{
static const float multipliers[16] = {
0.0f,
1.0f / ((1 << 1) - 1),
1.0f / ((1 << 2) - 1),
1.0f / ((1 << 3) - 1),
1.0f / ((1 << 4) - 1),
1.0f / ((1 << 5) - 1),
1.0f / ((1 << 6) - 1),
1.0f / ((1 << 7) - 1),
1.0f / ((1 << 8) - 1),
1.0f / ((1 << 9) - 1),
1.0f / ((1 << 10) - 1),
1.0f / ((1 << 11) - 1),
1.0f / ((1 << 12) - 1),
1.0f / ((1 << 13) - 1),
1.0f / ((1 << 14) - 1),
1.0f / ((1 << 15) - 1),
};
int a_size, r_size, g_size, b_size;
int a_shift, r_shift, g_shift, b_shift;
float a_mul, r_mul, g_mul, b_mul;
uint32_t a_mask, r_mask, g_mask, b_mask;
int i;
if (!PIXMAN_FORMAT_VIS (format))
format = PIXMAN_a8r8g8b8;
/*
* Determine the sizes of each component and the masks and shifts
* required to extract them from the source pixel.
*/
a_size = PIXMAN_FORMAT_A (format);
r_size = PIXMAN_FORMAT_R (format);
g_size = PIXMAN_FORMAT_G (format);
b_size = PIXMAN_FORMAT_B (format);
a_shift = 32 - a_size;
r_shift = 24 - r_size;
g_shift = 16 - g_size;
b_shift = 8 - b_size;
a_mask = ((1 << a_size) - 1);
r_mask = ((1 << r_size) - 1);
g_mask = ((1 << g_size) - 1);
b_mask = ((1 << b_size) - 1);
a_mul = multipliers[a_size];
r_mul = multipliers[r_size];
g_mul = multipliers[g_size];
b_mul = multipliers[b_size];
/* Start at the end so that we can do the expansion in place
* when src == dst
*/
for (i = width - 1; i >= 0; i--)
{
const uint32_t pixel = src[i];
dst[i].a = a_mask? ((pixel >> a_shift) & a_mask) * a_mul : 1.0f;
dst[i].r = ((pixel >> r_shift) & r_mask) * r_mul;
dst[i].g = ((pixel >> g_shift) & g_mask) * g_mul;
dst[i].b = ((pixel >> b_shift) & b_mask) * b_mul;
}
}
uint16_t
pixman_float_to_unorm (float f, int n_bits)
{
return float_to_unorm (f, n_bits);
}
float
pixman_unorm_to_float (uint16_t u, int n_bits)
{
return unorm_to_float (u, n_bits);
}
void
pixman_contract_from_float (uint32_t *dst,
const argb_t *src,
int width)
{
int i;
for (i = 0; i < width; ++i)
{
uint8_t a, r, g, b;
a = float_to_unorm (src[i].a, 8);
r = float_to_unorm (src[i].r, 8);
g = float_to_unorm (src[i].g, 8);
b = float_to_unorm (src[i].b, 8);
dst[i] = (a << 24) | (r << 16) | (g << 8) | (b << 0);
}
}
uint32_t *
_pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask)
{
return iter->buffer;
}
#define N_TMP_BOXES (16)
pixman_bool_t
pixman_region16_copy_from_region32 (pixman_region16_t *dst,
pixman_region32_t *src)
{
int n_boxes, i;
pixman_box32_t *boxes32;
pixman_box16_t *boxes16;
pixman_bool_t retval;
boxes32 = pixman_region32_rectangles (src, &n_boxes);
boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t));
if (!boxes16)
return FALSE;
for (i = 0; i < n_boxes; ++i)
{
boxes16[i].x1 = boxes32[i].x1;
boxes16[i].y1 = boxes32[i].y1;
boxes16[i].x2 = boxes32[i].x2;
boxes16[i].y2 = boxes32[i].y2;
}
pixman_region_fini (dst);
retval = pixman_region_init_rects (dst, boxes16, n_boxes);
free (boxes16);
return retval;
}
pixman_bool_t
pixman_region32_copy_from_region16 (pixman_region32_t *dst,
pixman_region16_t *src)
{
int n_boxes, i;
pixman_box16_t *boxes16;
pixman_box32_t *boxes32;
pixman_box32_t tmp_boxes[N_TMP_BOXES];
pixman_bool_t retval;
boxes16 = pixman_region_rectangles (src, &n_boxes);
if (n_boxes > N_TMP_BOXES)
boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t));
else
boxes32 = tmp_boxes;
if (!boxes32)
return FALSE;
for (i = 0; i < n_boxes; ++i)
{
boxes32[i].x1 = boxes16[i].x1;
boxes32[i].y1 = boxes16[i].y1;
boxes32[i].x2 = boxes16[i].x2;
boxes32[i].y2 = boxes16[i].y2;
}
pixman_region32_fini (dst);
retval = pixman_region32_init_rects (dst, boxes32, n_boxes);
if (boxes32 != tmp_boxes)
free (boxes32);
return retval;
}
/* This function is exported for the sake of the test suite and not part
* of the ABI.
*/
PIXMAN_EXPORT pixman_implementation_t *
_pixman_internal_only_get_implementation (void)
{
return get_implementation ();
}
#ifdef DEBUG
void
_pixman_log_error (const char *function, const char *message)
{
static int n_messages = 0;
if (n_messages < 10)
{
fprintf (stderr,
"*** BUG ***\n"
"In %s: %s\n"
"Set a breakpoint on '_pixman_log_error' to debug\n\n",
function, message);
n_messages++;
}
}
#endif

View file

@ -0,0 +1,50 @@
/*
* Copyright © 2008 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Author: Carl D. Worth <cworth@cworth.org>
*/
#ifndef PIXMAN_VERSION_H__
#define PIXMAN_VERSION_H__
#ifndef PIXMAN_H__
# error pixman-version.h should only be included by pixman.h
#endif
#define PIXMAN_VERSION_MAJOR 0
#define PIXMAN_VERSION_MINOR 27
#define PIXMAN_VERSION_MICRO 1
#define PIXMAN_VERSION_STRING "0.27.1"
#define PIXMAN_VERSION_ENCODE(major, minor, micro) ( \
((major) * 10000) \
+ ((minor) * 100) \
+ ((micro) * 1))
#define PIXMAN_VERSION PIXMAN_VERSION_ENCODE( \
PIXMAN_VERSION_MAJOR, \
PIXMAN_VERSION_MINOR, \
PIXMAN_VERSION_MICRO)
#endif /* PIXMAN_VERSION_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,263 @@
#ifndef MMX_X64_H_INCLUDED
#define MMX_X64_H_INCLUDED
/* Implementation of x64 MMX substitition functions, before
* pixman is reimplemented not to use __m64 type on Visual C++
*
* Copyright (C)2009 by George Yohng
* Released in public domain.
*/
#include <intrin.h>
#define M64C(a) (*(const __m64 *)(&a))
#define M64U(a) (*(const unsigned long long *)(&a))
__inline __m64
_m_from_int (int a)
{
long long i64 = a;
return M64C (i64);
}
__inline __m64
_mm_setzero_si64 ()
{
long long i64 = 0;
return M64C (i64);
}
__inline __m64
_mm_set_pi32 (int i1, int i0)
{
unsigned long long i64 = ((unsigned)i0) + (((unsigned long long)(unsigned)i1) << 32);
return M64C (i64);
}
__inline void
_m_empty ()
{
}
__inline __m64
_mm_set1_pi16 (short w)
{
unsigned long long i64 = ((unsigned long long)(unsigned short)(w)) * 0x0001000100010001ULL;
return M64C (i64);
}
__inline int
_m_to_int (__m64 m)
{
return m.m64_i32[0];
}
__inline __m64
_mm_movepi64_pi64 (__m128i a)
{
return M64C (a.m128i_i64[0]);
}
__inline __m64
_m_pand (__m64 a, __m64 b)
{
unsigned long long i64 = M64U (a) & M64U (b);
return M64C (i64);
}
__inline __m64
_m_por (__m64 a, __m64 b)
{
unsigned long long i64 = M64U (a) | M64U (b);
return M64C (i64);
}
__inline __m64
_m_pxor (__m64 a, __m64 b)
{
unsigned long long i64 = M64U (a) ^ M64U (b);
return M64C (i64);
}
__inline __m64
_m_pmulhuw (__m64 a, __m64 b) /* unoptimized */
{
unsigned short d[4] =
{
(unsigned short)((((unsigned)a.m64_u16[0]) * b.m64_u16[0]) >> 16),
(unsigned short)((((unsigned)a.m64_u16[1]) * b.m64_u16[1]) >> 16),
(unsigned short)((((unsigned)a.m64_u16[2]) * b.m64_u16[2]) >> 16),
(unsigned short)((((unsigned)a.m64_u16[3]) * b.m64_u16[3]) >> 16)
};
return M64C (d[0]);
}
__inline __m64
_m_pmullw2 (__m64 a, __m64 b) /* unoptimized */
{
unsigned short d[4] =
{
(unsigned short)((((unsigned)a.m64_u16[0]) * b.m64_u16[0])),
(unsigned short)((((unsigned)a.m64_u16[1]) * b.m64_u16[1])),
(unsigned short)((((unsigned)a.m64_u16[2]) * b.m64_u16[2])),
(unsigned short)((((unsigned)a.m64_u16[3]) * b.m64_u16[3]))
};
return M64C (d[0]);
}
__inline __m64
_m_pmullw (__m64 a, __m64 b) /* unoptimized */
{
unsigned long long x =
((unsigned long long)(unsigned short)((((unsigned)a.m64_u16[0]) * b.m64_u16[0]))) +
(((unsigned long long)(unsigned short)((((unsigned)a.m64_u16[1]) * b.m64_u16[1]))) << 16) +
(((unsigned long long)(unsigned short)((((unsigned)a.m64_u16[2]) * b.m64_u16[2]))) << 32) +
(((unsigned long long)(unsigned short)((((unsigned)a.m64_u16[3]) * b.m64_u16[3]))) << 48);
return M64C (x);
}
__inline __m64
_m_paddusb (__m64 a, __m64 b) /* unoptimized */
{
unsigned long long x = (M64U (a) & 0x00FF00FF00FF00FFULL) +
(M64U (b) & 0x00FF00FF00FF00FFULL);
unsigned long long y = ((M64U (a) >> 8) & 0x00FF00FF00FF00FFULL) +
((M64U (b) >> 8) & 0x00FF00FF00FF00FFULL);
x |= ((x & 0xFF00FF00FF00FF00ULL) >> 8) * 0xFF;
y |= ((y & 0xFF00FF00FF00FF00ULL) >> 8) * 0xFF;
x = (x & 0x00FF00FF00FF00FFULL) | ((y & 0x00FF00FF00FF00FFULL) << 8);
return M64C (x);
}
__inline __m64
_m_paddusw (__m64 a, __m64 b) /* unoptimized */
{
unsigned long long x = (M64U (a) & 0x0000FFFF0000FFFFULL) +
(M64U (b) & 0x0000FFFF0000FFFFULL);
unsigned long long y = ((M64U (a) >> 16) & 0x0000FFFF0000FFFFULL) +
((M64U (b) >> 16) & 0x0000FFFF0000FFFFULL);
x |= ((x & 0xFFFF0000FFFF0000) >> 16) * 0xFFFF;
y |= ((y & 0xFFFF0000FFFF0000) >> 16) * 0xFFFF;
x = (x & 0x0000FFFF0000FFFFULL) | ((y & 0x0000FFFF0000FFFFULL) << 16);
return M64C (x);
}
__inline __m64
_m_pshufw (__m64 a, int n) /* unoptimized */
{
unsigned short d[4] =
{
a.m64_u16[n & 3],
a.m64_u16[(n >> 2) & 3],
a.m64_u16[(n >> 4) & 3],
a.m64_u16[(n >> 6) & 3]
};
return M64C (d[0]);
}
__inline unsigned char
sat16 (unsigned short d)
{
if (d > 0xFF) return 0xFF;
else return d & 0xFF;
}
__inline __m64
_m_packuswb (__m64 m1, __m64 m2) /* unoptimized */
{
unsigned char d[8] =
{
sat16 (m1.m64_u16[0]),
sat16 (m1.m64_u16[1]),
sat16 (m1.m64_u16[2]),
sat16 (m1.m64_u16[3]),
sat16 (m2.m64_u16[0]),
sat16 (m2.m64_u16[1]),
sat16 (m2.m64_u16[2]),
sat16 (m2.m64_u16[3])
};
return M64C (d[0]);
}
__inline __m64 _m_punpcklbw (__m64 m1, __m64 m2) /* unoptimized */
{
unsigned char d[8] =
{
m1.m64_u8[0],
m2.m64_u8[0],
m1.m64_u8[1],
m2.m64_u8[1],
m1.m64_u8[2],
m2.m64_u8[2],
m1.m64_u8[3],
m2.m64_u8[3],
};
return M64C (d[0]);
}
__inline __m64 _m_punpckhbw (__m64 m1, __m64 m2) /* unoptimized */
{
unsigned char d[8] =
{
m1.m64_u8[4],
m2.m64_u8[4],
m1.m64_u8[5],
m2.m64_u8[5],
m1.m64_u8[6],
m2.m64_u8[6],
m1.m64_u8[7],
m2.m64_u8[7],
};
return M64C (d[0]);
}
__inline __m64 _m_psrlwi (__m64 a, int n) /* unoptimized */
{
unsigned short d[4] =
{
a.m64_u16[0] >> n,
a.m64_u16[1] >> n,
a.m64_u16[2] >> n,
a.m64_u16[3] >> n
};
return M64C (d[0]);
}
__inline __m64 _m_psrlqi (__m64 m, int n)
{
unsigned long long x = M64U (m) >> n;
return M64C (x);
}
__inline __m64 _m_psllqi (__m64 m, int n)
{
unsigned long long x = M64U (m) << n;
return M64C (x);
}
#endif /* MMX_X64_H_INCLUDED */

View file

@ -0,0 +1,241 @@
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, Inc.
*
* 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 SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* 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 "pixman-private.h"
#if defined(USE_X86_MMX) || defined (USE_SSE2)
/* The CPU detection code needs to be in a file not compiled with
* "-mmmx -msse", as gcc would generate CMOV instructions otherwise
* that would lead to SIGILL instructions on old CPUs that don't have
* it.
*/
typedef enum
{
X86_MMX = (1 << 0),
X86_MMX_EXTENSIONS = (1 << 1),
X86_SSE = (1 << 2) | X86_MMX_EXTENSIONS,
X86_SSE2 = (1 << 3),
X86_CMOV = (1 << 4)
} cpu_features_t;
#ifdef HAVE_GETISAX
#include <sys/auxv.h>
static cpu_features_t
detect_cpu_features (void)
{
cpu_features_t features = 0;
unsigned int result = 0;
if (getisax (&result, 1))
{
if (result & AV_386_CMOV)
features |= X86_CMOV;
if (result & AV_386_MMX)
features |= X86_MMX;
if (result & AV_386_AMD_MMX)
features |= X86_MMX_EXTENSIONS;
if (result & AV_386_SSE)
features |= X86_SSE;
if (result & AV_386_SSE2)
features |= X86_SSE2;
}
return features;
}
#else
#define _PIXMAN_X86_64 \
(defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64))
static pixman_bool_t
have_cpuid (void)
{
#if _PIXMAN_X86_64 || defined (_MSC_VER)
return TRUE;
#elif defined (__GNUC__)
uint32_t result;
__asm__ volatile (
"pushf" "\n\t"
"pop %%eax" "\n\t"
"mov %%eax, %%ecx" "\n\t"
"xor $0x00200000, %%eax" "\n\t"
"push %%eax" "\n\t"
"popf" "\n\t"
"pushf" "\n\t"
"pop %%eax" "\n\t"
"xor %%ecx, %%eax" "\n\t"
"mov %%eax, %0" "\n\t"
: "=r" (result)
:
: "%eax", "%ecx");
return !!result;
#else
#error "Unknown compiler"
#endif
}
#ifdef _MSC_VER
#include <intrin.h> /* for __cpuid */
#endif
static void
pixman_cpuid (uint32_t feature,
uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
{
#if defined (__GNUC__)
#if _PIXMAN_X86_64
__asm__ volatile (
"cpuid" "\n\t"
: "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
: "a" (feature));
#else
/* On x86-32 we need to be careful about the handling of %ebx
* and %esp. We can't declare either one as clobbered
* since they are special registers (%ebx is the "PIC
* register" holding an offset to global data, %esp the
* stack pointer), so we need to make sure that %ebx is
* preserved, and that %esp has its original value when
* accessing the output operands.
*/
__asm__ volatile (
"xchg %%ebx, %1" "\n\t"
"cpuid" "\n\t"
"xchg %%ebx, %1" "\n\t"
: "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d)
: "a" (feature));
#endif
#elif defined (_MSC_VER)
int info[4];
__cpuid (info, feature);
*a = info[0];
*b = info[1];
*c = info[2];
*d = info[3];
#else
#error Unknown compiler
#endif
}
static cpu_features_t
detect_cpu_features (void)
{
uint32_t a, b, c, d;
cpu_features_t features = 0;
if (!have_cpuid())
return features;
/* Get feature bits */
pixman_cpuid (0x01, &a, &b, &c, &d);
if (d & (1 << 15))
features |= X86_CMOV;
if (d & (1 << 23))
features |= X86_MMX;
if (d & (1 << 25))
features |= X86_SSE;
if (d & (1 << 26))
features |= X86_SSE2;
/* Check for AMD specific features */
if ((features & X86_MMX) && !(features & X86_SSE))
{
char vendor[13];
/* Get vendor string */
memset (vendor, 0, sizeof vendor);
pixman_cpuid (0x00, &a, &b, &c, &d);
memcpy (vendor + 0, &b, 4);
memcpy (vendor + 4, &d, 4);
memcpy (vendor + 8, &c, 4);
if (strcmp (vendor, "AuthenticAMD") == 0 ||
strcmp (vendor, "Geode by NSC") == 0)
{
pixman_cpuid (0x80000000, &a, &b, &c, &d);
if (a >= 0x80000001)
{
pixman_cpuid (0x80000001, &a, &b, &c, &d);
if (d & (1 << 22))
features |= X86_MMX_EXTENSIONS;
}
}
}
return features;
}
#endif
static pixman_bool_t
have_feature (cpu_features_t feature)
{
static pixman_bool_t initialized;
static cpu_features_t features;
if (!initialized)
{
features = detect_cpu_features();
initialized = TRUE;
}
return (features & feature) == feature;
}
#endif
pixman_implementation_t *
_pixman_x86_get_implementations (pixman_implementation_t *imp)
{
#define MMX_BITS (X86_MMX | X86_MMX_EXTENSIONS)
#define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2)
#ifdef USE_X86_MMX
if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS))
imp = _pixman_implementation_create_mmx (imp);
#endif
#ifdef USE_SSE2
if (!_pixman_disabled ("sse2") && have_feature (SSE2_BITS))
imp = _pixman_implementation_create_sse2 (imp);
#endif
return imp;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,478 @@
Roadmap
- Move all the fetchers etc. into pixman-image to make pixman-compose.c
less intimidating.
DONE
- Make combiners for unified alpha take a mask argument. That way
we won't need two separate paths for unified vs component in the
general compositing code.
DONE, except that the Altivec code needs to be updated. Luca is
looking into that.
- Delete separate 'unified alpha' path
DONE
- Split images into their own files
DONE
- Split the gradient walker code out into its own file
DONE
- Add scanline getters per image
DONE
- Generic 64 bit fetcher
DONE
- Split fast path tables into their respective architecture dependent
files.
See "Render Algorithm" below for rationale
Images will eventually have these virtual functions:
get_scanline()
get_scanline_wide()
get_pixel()
get_pixel_wide()
get_untransformed_pixel()
get_untransformed_pixel_wide()
get_unfiltered_pixel()
get_unfiltered_pixel_wide()
store_scanline()
store_scanline_wide()
1.
Initially we will just have get_scanline() and get_scanline_wide();
these will be based on the ones in pixman-compose. Hopefully this will
reduce the complexity in pixman_composite_rect_general().
Note that there is access considerations - the compose function is
being compiled twice.
2.
Split image types into their own source files. Export noop virtual
reinit() call. Call this whenever a property of the image changes.
3.
Split the get_scanline() call into smaller functions that are
initialized by the reinit() call.
The Render Algorithm:
(first repeat, then filter, then transform, then clip)
Starting from a destination pixel (x, y), do
1 x = x - xDst + xSrc
y = y - yDst + ySrc
2 reject pixel that is outside the clip
This treats clipping as something that happens after
transformation, which I think is correct for client clips. For
hierarchy clips it is wrong, but who really cares? Without
GraphicsExposes hierarchy clips are basically irrelevant. Yes,
you could imagine cases where the pixels of a subwindow of a
redirected, transformed window should be treated as
transparent. I don't really care
Basically, I think the render spec should say that pixels that
are unavailable due to the hierarcy have undefined content,
and that GraphicsExposes are not generated. Ie., basically
that using non-redirected windows as sources is fail. This is
at least consistent with the current implementation and we can
update the spec later if someone makes it work.
The implication for render is that it should stop passing the
hierarchy clip to pixman. In pixman, if a souce image has a
clip it should be used in computing the composite region and
nowhere else, regardless of what "has_client_clip" says. The
default should be for there to not be any clip.
I would really like to get rid of the client clip as well for
source images, but unfortunately there is at least one
application in the wild that uses them.
3 Transform pixel: (x, y) = T(x, y)
4 Call p = GetUntransformedPixel (x, y)
5 If the image has an alpha map, then
Call GetUntransformedPixel (x, y) on the alpha map
add resulting alpha channel to p
return p
Where GetUnTransformedPixel is:
6 switch (filter)
{
case NEAREST:
return GetUnfilteredPixel (x, y);
break;
case BILINEAR:
return GetUnfilteredPixel (...) // 4 times
break;
case CONVOLUTION:
return GetUnfilteredPixel (...) // as many times as necessary.
break;
}
Where GetUnfilteredPixel (x, y) is
7 switch (repeat)
{
case REPEAT_NORMAL:
case REPEAT_PAD:
case REPEAT_REFLECT:
// adjust x, y as appropriate
break;
case REPEAT_NONE:
if (x, y) is outside image bounds
return 0;
break;
}
return GetRawPixel(x, y)
Where GetRawPixel (x, y) is
8 Compute the pixel in question, depending on image type.
For gradients, repeat has a totally different meaning, so
UnfilteredPixel() and RawPixel() must be the same function so that
gradients can do their own repeat algorithm.
So, the GetRawPixel
for bits must deal with repeats
for gradients must deal with repeats (differently)
for solids, should ignore repeats.
for polygons, when we add them, either ignore repeats or do
something similar to bits (in which case, we may want an extra
layer of indirection to modify the coordinates).
It is then possible to build things like "get scanline" or "get tile" on
top of this. In the simplest case, just repeatedly calling GetPixel()
would work, but specialized get_scanline()s or get_tile()s could be
plugged in for common cases.
By not plugging anything in for images with access functions, we only
have to compile the pixel functions twice, not the scanline functions.
And we can get rid of fetchers for the bizarre formats that no one
uses. Such as b2g3r3 etc. r1g2b1? Seriously? It is also worth
considering a generic format based pixel fetcher for these edge cases.
Since the actual routines depend on the image attributes, the images
must be notified when those change and update their function pointers
appropriately. So there should probably be a virtual function called
(* reinit) or something like that.
There will also be wide fetchers for both pixels and lines. The line
fetcher will just call the wide pixel fetcher. The wide pixel fetcher
will just call expand, except for 10 bit formats.
Rendering pipeline:
Drawable:
0. if (picture has alpha map)
0.1. Position alpha map according to the alpha_x/alpha_y
0.2. Where the two drawables intersect, the alpha channel
Replace the alpha channel of source with the one
from the alpha map. Replacement only takes place
in the intersection of the two drawables' geometries.
1. Repeat the drawable according to the repeat attribute
2. Reconstruct a continuous image according to the filter
3. Transform according to the transform attribute
4. Position image such that src_x, src_y is over dst_x, dst_y
5. Sample once per destination pixel
6. Clip. If a pixel is not within the source clip, then no
compositing takes place at that pixel. (Ie., it's *not*
treated as 0).
Sampling a drawable:
- If the channel does not have an alpha channel, the pixels in it
are treated as opaque.
Note on reconstruction:
- The top left pixel has coordinates (0.5, 0.5) and pixels are
spaced 1 apart.
Gradient:
1. Unless gradient type is conical, repeat the underlying (0, 1)
gradient according to the repeat attribute
2. Integrate the gradient across the plane according to type.
3. Transform according to transform attribute
4. Position gradient
5. Sample once per destination pixel.
6. Clip
Solid Fill:
1. Repeat has no effect
2. Image is already continuous and defined for the entire plane
3. Transform has no effect
4. Positioning has no effect
5. Sample once per destination pixel.
6. Clip
Polygon:
1. Repeat has no effect
2. Image is already continuous and defined on the whole plane
3. Transform according to transform attribute
4. Position image
5. Supersample 15x17 per destination pixel.
6. Clip
Possibly interesting additions:
- More general transformations, such as warping, or general
shading.
- Shader image where a function is called to generate the
pixel (ie., uploading assembly code).
- Resampling kernels
In principle the polygon image uses a 15x17 box filter for
resampling. If we allow general resampling filters, then we
get all the various antialiasing types for free.
Bilinear downsampling looks terrible and could be much
improved by a resampling filter. NEAREST reconstruction
combined with a box resampling filter is what GdkPixbuf
does, I believe.
Useful for high frequency gradients as well.
(Note that the difference between a reconstruction and a
resampling filter is mainly where in the pipeline they
occur. High quality resampling should use a correctly
oriented kernel so it should happen after transformation.
An implementation can transform the resampling kernel and
convolve it with the reconstruction if it so desires, but it
will need to deal with the fact that the resampling kernel
will not necessarily be pixel aligned.
"Output kernels"
One could imagine doing the resampling after compositing,
ie., for each destination pixel sample each source image 16
times, then composite those subpixels individually, then
finally apply a kernel.
However, this is effectively the same as full screen
antialiasing, which is a simpler way to think about it. So
resampling kernels may make sense for individual images, but
not as a post-compositing step.
Fullscreen AA is inefficient without chained compositing
though. Consider an (image scaled up to oversample size IN
some polygon) scaled down to screen size. With the current
implementation, there will be a huge temporary. With chained
compositing, the whole thing ends up being equivalent to the
output kernel from above.
- Color space conversion
The complete model here is that each surface has a color
space associated with it and that the compositing operation
also has one associated with it. Note also that gradients
should have associcated colorspaces.
- Dithering
If people dither something that is already dithered, it will
look terrible, but don't do that, then. (Dithering happens
after resampling if at all - what is the relationship
with color spaces? Presumably dithering should happen in linear
intensity space).
- Floating point surfaces, 16, 32 and possibly 64 bit per
channel.
Maybe crack:
- Glyph polygons
If glyphs could be given as polygons, they could be
positioned and rasterized more accurately. The glyph
structure would need subpixel positioning though.
- Luminance vs. coverage for the alpha channel
Whether the alpha channel should be interpreted as luminance
modulation or as coverage (intensity modulation). This is a
bit of a departure from the rendering model though. It could
also be considered whether it should be possible to have
both channels in the same drawable.
- Alternative for component alpha
- Set component-alpha on the output image.
- This means each of the components are sampled
independently and composited in the corresponding
channel only.
- Have 3 x oversampled mask
- Scale it down by 3 horizontally, with [ 1/3, 1/3, 1/3 ]
resampling filter.
Is this equivalent to just using a component alpha mask?
Incompatible changes:
- Gradients could be specified with premultiplied colors. (You
can use a mask to get things like gradients from solid red to
transparent red.
Refactoring pixman
The pixman code is not particularly nice to put it mildly. Among the
issues are
- inconsistent naming style (fb vs Fb, camelCase vs
underscore_naming). Sometimes there is even inconsistency *within*
one name.
fetchProc32 ACCESS(pixman_fetchProcForPicture32)
may be one of the uglies names ever created.
coding style:
use the one from cairo except that pixman uses this brace style:
while (blah)
{
}
Format do while like this:
do
{
}
while (...);
- PIXMAN_COMPOSITE_RECT_GENERAL() is horribly complex
- switch case logic in pixman-access.c
Instead it would be better to just store function pointers in the
image objects themselves,
get_pixel()
get_scanline()
- Much of the scanline fetching code is for formats that no one
ever uses. a2r2g2b2 anyone?
It would probably be worthwhile having a generic fetcher for any
pixman format whatsoever.
- Code related to particular image types should be split into individual
files.
pixman-bits-image.c
pixman-linear-gradient-image.c
pixman-radial-gradient-image.c
pixman-solid-image.c
- Fast path code should be split into files based on architecture:
pixman-mmx-fastpath.c
pixman-sse2-fastpath.c
pixman-c-fastpath.c
etc.
Each of these files should then export a fastpath table, which would
be declared in pixman-private.h. This should allow us to get rid
of the pixman-mmx.h files.
The fast path table should describe each fast path. Ie there should
be bitfields indicating what things the fast path can handle, rather than
like now where it is only allowed to take one format per src/mask/dest. Ie.,
{
FAST_a8r8g8b8 | FAST_x8r8g8b8,
FAST_null,
FAST_x8r8g8b8,
FAST_repeat_normal | FAST_repeat_none,
the_fast_path
}
There should then be *one* file that implements pixman_image_composite().
This should do this:
optimize_operator();
convert 1x1 repeat to solid (actually this should be done at
image creation time).
is there a useful fastpath?
There should be a file called pixman-cpu.c that contains all the
architecture specific stuff to detect what CPU features we have.
Issues that must be kept in mind:
- we need accessor code to be preserved
- maybe there should be a "store_scanline" too?
Is this sufficient?
We should preserve the optimization where the
compositing happens directly in the destination
whenever possible.
- It should be possible to create GPU samplers from the
images.
The "horizontal" classification should be a bit in the image, the
"vertical" classification should just happen inside the gradient
file. Note though that
(a) these will change if the tranformation/repeat changes.
(b) at the moment the optimization for linear gradients
takes the source rectangle into account. Presumably
this is to also optimize the case where the gradient
is close enough to horizontal?
Who is responsible for repeats? In principle it should be the scanline
fetch. Right now NORMAL repeats are handled by walk_composite_region()
while other repeats are handled by the scanline code.
(Random note on filtering: do you filter before or after
transformation? Hardware is going to filter after transformation;
this is also what pixman does currently). It's not completely clear
what filtering *after* transformation means. One thing that might look
good would be to do *supersampling*, ie., compute multiple subpixels
per destination pixel, then average them together.