13c5ee0fc482e93912b9b090d0df1af496288a702John Reck/*
23c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Copyright © 2013 The Android Open Source Project
33c5ee0fc482e93912b9b090d0df1af496288a702John Reck *
43c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Permission is hereby granted, free of charge, to any person obtaining a
53c5ee0fc482e93912b9b090d0df1af496288a702John Reck * copy of this software and associated documentation files (the "Software"),
63c5ee0fc482e93912b9b090d0df1af496288a702John Reck * to deal in the Software without restriction, including without limitation
73c5ee0fc482e93912b9b090d0df1af496288a702John Reck * the rights to use, copy, modify, merge, publish, distribute, sublicense,
83c5ee0fc482e93912b9b090d0df1af496288a702John Reck * and/or sell copies of the Software, and to permit persons to whom the
93c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Software is furnished to do so, subject to the following conditions:
103c5ee0fc482e93912b9b090d0df1af496288a702John Reck *
113c5ee0fc482e93912b9b090d0df1af496288a702John Reck * The above copyright notice and this permission notice (including the next
123c5ee0fc482e93912b9b090d0df1af496288a702John Reck * paragraph) shall be included in all copies or substantial portions of the
133c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Software.
143c5ee0fc482e93912b9b090d0df1af496288a702John Reck *
153c5ee0fc482e93912b9b090d0df1af496288a702John Reck * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
163c5ee0fc482e93912b9b090d0df1af496288a702John Reck * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
173c5ee0fc482e93912b9b090d0df1af496288a702John Reck * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
183c5ee0fc482e93912b9b090d0df1af496288a702John Reck * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
193c5ee0fc482e93912b9b090d0df1af496288a702John Reck * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
203c5ee0fc482e93912b9b090d0df1af496288a702John Reck * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
213c5ee0fc482e93912b9b090d0df1af496288a702John Reck * DEALINGS IN THE SOFTWARE.
223c5ee0fc482e93912b9b090d0df1af496288a702John Reck */
233c5ee0fc482e93912b9b090d0df1af496288a702John Reck/*
243c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Copyright © 2000 SuSE, Inc.
253c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Copyright © 2007 Red Hat, Inc.
263c5ee0fc482e93912b9b090d0df1af496288a702John Reck *
273c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Permission to use, copy, modify, distribute, and sell this software and its
283c5ee0fc482e93912b9b090d0df1af496288a702John Reck * documentation for any purpose is hereby granted without fee, provided that
293c5ee0fc482e93912b9b090d0df1af496288a702John Reck * the above copyright notice appear in all copies and that both that
303c5ee0fc482e93912b9b090d0df1af496288a702John Reck * copyright notice and this permission notice appear in supporting
313c5ee0fc482e93912b9b090d0df1af496288a702John Reck * documentation, and that the name of SuSE not be used in advertising or
323c5ee0fc482e93912b9b090d0df1af496288a702John Reck * publicity pertaining to distribution of the software without specific,
333c5ee0fc482e93912b9b090d0df1af496288a702John Reck * written prior permission.  SuSE makes no representations about the
343c5ee0fc482e93912b9b090d0df1af496288a702John Reck * suitability of this software for any purpose.  It is provided "as is"
353c5ee0fc482e93912b9b090d0df1af496288a702John Reck * without express or implied warranty.
363c5ee0fc482e93912b9b090d0df1af496288a702John Reck *
373c5ee0fc482e93912b9b090d0df1af496288a702John Reck * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
383c5ee0fc482e93912b9b090d0df1af496288a702John Reck * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
393c5ee0fc482e93912b9b090d0df1af496288a702John Reck * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
403c5ee0fc482e93912b9b090d0df1af496288a702John Reck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
413c5ee0fc482e93912b9b090d0df1af496288a702John Reck * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
423c5ee0fc482e93912b9b090d0df1af496288a702John Reck * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
433c5ee0fc482e93912b9b090d0df1af496288a702John Reck *
443c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Author:  Keith Packard, SuSE, Inc.
453c5ee0fc482e93912b9b090d0df1af496288a702John Reck */
463c5ee0fc482e93912b9b090d0df1af496288a702John Reck/*
473c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Copyright © 2009 ARM Ltd, Movial Creative Technologies Oy
483c5ee0fc482e93912b9b090d0df1af496288a702John Reck *
493c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Permission to use, copy, modify, distribute, and sell this software and its
503c5ee0fc482e93912b9b090d0df1af496288a702John Reck * documentation for any purpose is hereby granted without fee, provided that
513c5ee0fc482e93912b9b090d0df1af496288a702John Reck * the above copyright notice appear in all copies and that both that
523c5ee0fc482e93912b9b090d0df1af496288a702John Reck * copyright notice and this permission notice appear in supporting
533c5ee0fc482e93912b9b090d0df1af496288a702John Reck * documentation, and that the name of ARM Ltd not be used in
543c5ee0fc482e93912b9b090d0df1af496288a702John Reck * advertising or publicity pertaining to distribution of the software without
553c5ee0fc482e93912b9b090d0df1af496288a702John Reck * specific, written prior permission.  ARM Ltd makes no
563c5ee0fc482e93912b9b090d0df1af496288a702John Reck * representations about the suitability of this software for any purpose.  It
573c5ee0fc482e93912b9b090d0df1af496288a702John Reck * is provided "as is" without express or implied warranty.
583c5ee0fc482e93912b9b090d0df1af496288a702John Reck *
593c5ee0fc482e93912b9b090d0df1af496288a702John Reck * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
603c5ee0fc482e93912b9b090d0df1af496288a702John Reck * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
613c5ee0fc482e93912b9b090d0df1af496288a702John Reck * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
623c5ee0fc482e93912b9b090d0df1af496288a702John Reck * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
633c5ee0fc482e93912b9b090d0df1af496288a702John Reck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
643c5ee0fc482e93912b9b090d0df1af496288a702John Reck * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
653c5ee0fc482e93912b9b090d0df1af496288a702John Reck * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
663c5ee0fc482e93912b9b090d0df1af496288a702John Reck * SOFTWARE.
673c5ee0fc482e93912b9b090d0df1af496288a702John Reck *
683c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Author:  Ian Rickards (ian.rickards@arm.com)
693c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Author:  Jonathan Morton (jonathan.morton@movial.com)
703c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Author:  Markku Vire (markku.vire@movial.com)
713c5ee0fc482e93912b9b090d0df1af496288a702John Reck *
723c5ee0fc482e93912b9b090d0df1af496288a702John Reck */
733c5ee0fc482e93912b9b090d0df1af496288a702John Reck
743c5ee0fc482e93912b9b090d0df1af496288a702John Reck#include "config.h"
753c5ee0fc482e93912b9b090d0df1af496288a702John Reck#include "pixman-android.h"
763c5ee0fc482e93912b9b090d0df1af496288a702John Reck#include "pixman-private.h"
775e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck#include <cpu-features.h>
783c5ee0fc482e93912b9b090d0df1af496288a702John Reck
795e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reckstatic force_inline void scaled_nearest_scanline_8888_8888_none_SRC(
805e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        uint32_t *dst, const uint32_t *src, int32_t w, pixman_fixed_t vx,
815e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        pixman_fixed_t unit_x, pixman_fixed_t src_width_fixed) {
825e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    uint32_t d;
835e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    uint32_t s1, s2;
845e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    uint8_t a1, a2;
855e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    int x1, x2;
863c5ee0fc482e93912b9b090d0df1af496288a702John Reck
875e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    while ((w -= 2) >= 0) {
885e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        x1 = pixman_fixed_to_int(vx);
895e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        vx += unit_x;
905e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        s1 = *(src + x1);
915e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        x2 = pixman_fixed_to_int(vx);
925e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        vx += unit_x;
935e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        s2 = *(src + x2);
945e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        *dst++ = s1;
955e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        *dst++ = s2;
965e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    }
975e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    if (w & 1) {
985e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        x1 = pixman_fixed_to_int(vx);
995e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        s1 = *(src + x1);
1005e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        *dst++ = s1;
1015e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    }
1023c5ee0fc482e93912b9b090d0df1af496288a702John Reck}
1033c5ee0fc482e93912b9b090d0df1af496288a702John Reck
1045e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reckstatic force_inline int pixman_fixed_to_bilinear_weight(pixman_fixed_t x) {
1053c5ee0fc482e93912b9b090d0df1af496288a702John Reck    return (x >> (16 - BILINEAR_INTERPOLATION_BITS))
1063c5ee0fc482e93912b9b090d0df1af496288a702John Reck            & ((1 << BILINEAR_INTERPOLATION_BITS) - 1);
1073c5ee0fc482e93912b9b090d0df1af496288a702John Reck}
1083c5ee0fc482e93912b9b090d0df1af496288a702John Reck
1093c5ee0fc482e93912b9b090d0df1af496288a702John Reck/*
1103c5ee0fc482e93912b9b090d0df1af496288a702John Reck * For each scanline fetched from source image with PAD repeat:
1113c5ee0fc482e93912b9b090d0df1af496288a702John Reck * - calculate how many pixels need to be padded on the left side
1123c5ee0fc482e93912b9b090d0df1af496288a702John Reck * - calculate how many pixels need to be padded on the right side
1133c5ee0fc482e93912b9b090d0df1af496288a702John Reck * - update width to only count pixels which are fetched from the image
1143c5ee0fc482e93912b9b090d0df1af496288a702John Reck * All this information is returned via 'width', 'left_pad', 'right_pad'
1153c5ee0fc482e93912b9b090d0df1af496288a702John Reck * arguments. The code is assuming that 'unit_x' is positive.
1163c5ee0fc482e93912b9b090d0df1af496288a702John Reck *
1173c5ee0fc482e93912b9b090d0df1af496288a702John Reck * Note: 64-bit math is used in order to avoid potential overflows, which
1183c5ee0fc482e93912b9b090d0df1af496288a702John Reck *       is probably excessive in many cases. This particular function
1193c5ee0fc482e93912b9b090d0df1af496288a702John Reck *       may need its own correctness test and performance tuning.
1203c5ee0fc482e93912b9b090d0df1af496288a702John Reck */
1213c5ee0fc482e93912b9b090d0df1af496288a702John Reckstatic force_inline void pad_repeat_get_scanline_bounds(
1223c5ee0fc482e93912b9b090d0df1af496288a702John Reck        int32_t source_image_width, pixman_fixed_t vx, pixman_fixed_t unit_x,
1233c5ee0fc482e93912b9b090d0df1af496288a702John Reck        int32_t * width, int32_t * left_pad, int32_t * right_pad) {
1243c5ee0fc482e93912b9b090d0df1af496288a702John Reck    int64_t max_vx = (int64_t) source_image_width << 16;
1253c5ee0fc482e93912b9b090d0df1af496288a702John Reck    int64_t tmp;
1263c5ee0fc482e93912b9b090d0df1af496288a702John Reck    if (vx < 0) {
1273c5ee0fc482e93912b9b090d0df1af496288a702John Reck        tmp = ((int64_t) unit_x - 1 - vx) / unit_x;
1283c5ee0fc482e93912b9b090d0df1af496288a702John Reck        if (tmp > *width) {
1293c5ee0fc482e93912b9b090d0df1af496288a702John Reck            *left_pad = *width;
1303c5ee0fc482e93912b9b090d0df1af496288a702John Reck            *width = 0;
1313c5ee0fc482e93912b9b090d0df1af496288a702John Reck        } else {
1323c5ee0fc482e93912b9b090d0df1af496288a702John Reck            *left_pad = (int32_t) tmp;
1333c5ee0fc482e93912b9b090d0df1af496288a702John Reck            *width -= (int32_t) tmp;
1343c5ee0fc482e93912b9b090d0df1af496288a702John Reck        }
1353c5ee0fc482e93912b9b090d0df1af496288a702John Reck    } else {
1363c5ee0fc482e93912b9b090d0df1af496288a702John Reck        *left_pad = 0;
1373c5ee0fc482e93912b9b090d0df1af496288a702John Reck    }
1383c5ee0fc482e93912b9b090d0df1af496288a702John Reck    tmp = ((int64_t) unit_x - 1 - vx + max_vx) / unit_x - *left_pad;
1393c5ee0fc482e93912b9b090d0df1af496288a702John Reck    if (tmp < 0) {
1403c5ee0fc482e93912b9b090d0df1af496288a702John Reck        *right_pad = *width;
1413c5ee0fc482e93912b9b090d0df1af496288a702John Reck        *width = 0;
1423c5ee0fc482e93912b9b090d0df1af496288a702John Reck    } else if (tmp >= *width) {
1433c5ee0fc482e93912b9b090d0df1af496288a702John Reck        *right_pad = 0;
1443c5ee0fc482e93912b9b090d0df1af496288a702John Reck    } else {
1453c5ee0fc482e93912b9b090d0df1af496288a702John Reck        *right_pad = *width - (int32_t) tmp;
1463c5ee0fc482e93912b9b090d0df1af496288a702John Reck        *width = (int32_t) tmp;
1473c5ee0fc482e93912b9b090d0df1af496288a702John Reck    }
1483c5ee0fc482e93912b9b090d0df1af496288a702John Reck}
1493c5ee0fc482e93912b9b090d0df1af496288a702John Reck
1503c5ee0fc482e93912b9b090d0df1af496288a702John Reckstatic force_inline void bilinear_pad_repeat_get_scanline_bounds(
1513c5ee0fc482e93912b9b090d0df1af496288a702John Reck        int32_t source_image_width, pixman_fixed_t vx, pixman_fixed_t unit_x,
1523c5ee0fc482e93912b9b090d0df1af496288a702John Reck        int32_t * left_pad, int32_t * left_tz, int32_t * width,
1533c5ee0fc482e93912b9b090d0df1af496288a702John Reck        int32_t * right_tz, int32_t * right_pad) {
1543c5ee0fc482e93912b9b090d0df1af496288a702John Reck    int width1 = *width, left_pad1, right_pad1;
1553c5ee0fc482e93912b9b090d0df1af496288a702John Reck    int width2 = *width, left_pad2, right_pad2;
1563c5ee0fc482e93912b9b090d0df1af496288a702John Reck
1573c5ee0fc482e93912b9b090d0df1af496288a702John Reck    pad_repeat_get_scanline_bounds(source_image_width, vx, unit_x, &width1,
1583c5ee0fc482e93912b9b090d0df1af496288a702John Reck            &left_pad1, &right_pad1);
1593c5ee0fc482e93912b9b090d0df1af496288a702John Reck    pad_repeat_get_scanline_bounds(source_image_width, vx + pixman_fixed_1,
1603c5ee0fc482e93912b9b090d0df1af496288a702John Reck            unit_x, &width2, &left_pad2, &right_pad2);
1613c5ee0fc482e93912b9b090d0df1af496288a702John Reck
1623c5ee0fc482e93912b9b090d0df1af496288a702John Reck    *left_pad = left_pad2;
1633c5ee0fc482e93912b9b090d0df1af496288a702John Reck    *left_tz = left_pad1 - left_pad2;
1643c5ee0fc482e93912b9b090d0df1af496288a702John Reck    *right_tz = right_pad2 - right_pad1;
1653c5ee0fc482e93912b9b090d0df1af496288a702John Reck    *right_pad = right_pad1;
1663c5ee0fc482e93912b9b090d0df1af496288a702John Reck    *width -= *left_pad + *left_tz + *right_tz + *right_pad;
1673c5ee0fc482e93912b9b090d0df1af496288a702John Reck}
1683c5ee0fc482e93912b9b090d0df1af496288a702John Reck
1695e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck#ifdef USE_ARM_NEON
1705e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reckvoid pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon(uint32_t *dst,
1715e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        const uint32_t *top, const uint32_t *bottom, int wt, int wb,
1725e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        pixman_fixed_t x, pixman_fixed_t ux, int width);
1735e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck
1745e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reckstatic void android_bilinear_filter_neon(android_simple_image* src_image,
175780fc14f48491c5e922475d9e46226a7ca23179eJohn Reck        android_simple_image* dst_image, float scale, int src_x, int src_y) {
1763c5ee0fc482e93912b9b090d0df1af496288a702John Reck    int32_t src_width = src_image->width;
1773c5ee0fc482e93912b9b090d0df1af496288a702John Reck    int32_t src_height = src_image->height;
1783c5ee0fc482e93912b9b090d0df1af496288a702John Reck    pixman_vector_t v;
1793c5ee0fc482e93912b9b090d0df1af496288a702John Reck    int32_t left_pad, left_tz, right_tz, right_pad;
1803c5ee0fc482e93912b9b090d0df1af496288a702John Reck    pixman_fixed_t unit_x, unit_y;
1813c5ee0fc482e93912b9b090d0df1af496288a702John Reck    int32_t width = dst_image->width;
1823c5ee0fc482e93912b9b090d0df1af496288a702John Reck    int32_t height = dst_image->height;
1833c5ee0fc482e93912b9b090d0df1af496288a702John Reck    uint32_t dst_line = 0;
1843c5ee0fc482e93912b9b090d0df1af496288a702John Reck    uint32_t* dst;
1853c5ee0fc482e93912b9b090d0df1af496288a702John Reck    int y1, y2;
1863c5ee0fc482e93912b9b090d0df1af496288a702John Reck    pixman_fixed_t vx, vy;
187780fc14f48491c5e922475d9e46226a7ca23179eJohn Reck    /* reference point is the center of the pixel */
1880ccffae8bfc5eb66b3de3c361c3f449ff7126df2John Reck    v.vector[0] = pixman_double_to_fixed((src_x + 0.5f) * scale);
1890ccffae8bfc5eb66b3de3c361c3f449ff7126df2John Reck    v.vector[1] = pixman_double_to_fixed((src_y + 0.5f) * scale);
190780fc14f48491c5e922475d9e46226a7ca23179eJohn Reck    v.vector[2] = pixman_fixed_1;
1910ccffae8bfc5eb66b3de3c361c3f449ff7126df2John Reck    unit_x = unit_y = pixman_double_to_fixed(scale);
1923c5ee0fc482e93912b9b090d0df1af496288a702John Reck    vy = v.vector[1];
1933c5ee0fc482e93912b9b090d0df1af496288a702John Reck    bilinear_pad_repeat_get_scanline_bounds(src_width, v.vector[0], unit_x,
1943c5ee0fc482e93912b9b090d0df1af496288a702John Reck            &left_pad, &left_tz, &width, &right_tz, &right_pad);
1953c5ee0fc482e93912b9b090d0df1af496288a702John Reck    v.vector[0] += left_pad * unit_x;
1963c5ee0fc482e93912b9b090d0df1af496288a702John Reck    while (--height >= 0) {
1973c5ee0fc482e93912b9b090d0df1af496288a702John Reck        int weight1, weight2;
1983c5ee0fc482e93912b9b090d0df1af496288a702John Reck        dst_image->get_scanline(dst_image, (void**)(&dst), dst_line);
1993c5ee0fc482e93912b9b090d0df1af496288a702John Reck        dst_line++;
2003c5ee0fc482e93912b9b090d0df1af496288a702John Reck        vx = v.vector[0];
201780fc14f48491c5e922475d9e46226a7ca23179eJohn Reck        y1 = pixman_fixed_to_int(vy);
2023c5ee0fc482e93912b9b090d0df1af496288a702John Reck        weight2 = pixman_fixed_to_bilinear_weight(vy);
2033c5ee0fc482e93912b9b090d0df1af496288a702John Reck        if (weight2) {
204780fc14f48491c5e922475d9e46226a7ca23179eJohn Reck            /* both weight1 and weight2 are smaller than BILINEAR_INTERPOLATION_RANGE */
2053c5ee0fc482e93912b9b090d0df1af496288a702John Reck            y2 = y1 + 1;
206780fc14f48491c5e922475d9e46226a7ca23179eJohn Reck            weight1 = BILINEAR_INTERPOLATION_RANGE - weight2;
2073c5ee0fc482e93912b9b090d0df1af496288a702John Reck        } else {
208780fc14f48491c5e922475d9e46226a7ca23179eJohn Reck            /* set both top and bottom row to the same scanline and tweak weights */
2093c5ee0fc482e93912b9b090d0df1af496288a702John Reck            y2 = y1;
210780fc14f48491c5e922475d9e46226a7ca23179eJohn Reck            weight1 = weight2 = BILINEAR_INTERPOLATION_RANGE / 2;
2113c5ee0fc482e93912b9b090d0df1af496288a702John Reck        }
2123c5ee0fc482e93912b9b090d0df1af496288a702John Reck        vy += unit_y;
2133c5ee0fc482e93912b9b090d0df1af496288a702John Reck        uint32_t buf1[2];
2143c5ee0fc482e93912b9b090d0df1af496288a702John Reck        uint32_t buf2[2];
2153c5ee0fc482e93912b9b090d0df1af496288a702John Reck        uint32_t* src1;
2163c5ee0fc482e93912b9b090d0df1af496288a702John Reck        uint32_t* src2;
217780fc14f48491c5e922475d9e46226a7ca23179eJohn Reck        /* handle top/bottom zero padding by just setting weights to 0 if needed */
2183c5ee0fc482e93912b9b090d0df1af496288a702John Reck        if (y1 < 0) {
2193c5ee0fc482e93912b9b090d0df1af496288a702John Reck            weight1 = 0;
2203c5ee0fc482e93912b9b090d0df1af496288a702John Reck            y1 = 0;
2213c5ee0fc482e93912b9b090d0df1af496288a702John Reck        }
2223c5ee0fc482e93912b9b090d0df1af496288a702John Reck        if (y1 >= src_height) {
2233c5ee0fc482e93912b9b090d0df1af496288a702John Reck            weight1 = 0;
2243c5ee0fc482e93912b9b090d0df1af496288a702John Reck            y1 = src_height - 1;
2253c5ee0fc482e93912b9b090d0df1af496288a702John Reck        }
2263c5ee0fc482e93912b9b090d0df1af496288a702John Reck        if (y2 < 0) {
2273c5ee0fc482e93912b9b090d0df1af496288a702John Reck            weight2 = 0;
2283c5ee0fc482e93912b9b090d0df1af496288a702John Reck            y2 = 0;
2293c5ee0fc482e93912b9b090d0df1af496288a702John Reck        }
2303c5ee0fc482e93912b9b090d0df1af496288a702John Reck        if (y2 >= src_height) {
2313c5ee0fc482e93912b9b090d0df1af496288a702John Reck            weight2 = 0;
2323c5ee0fc482e93912b9b090d0df1af496288a702John Reck            y2 = src_height - 1;
2333c5ee0fc482e93912b9b090d0df1af496288a702John Reck        }
2343c5ee0fc482e93912b9b090d0df1af496288a702John Reck        src_image->get_scanline(src_image, (void**)(&src1), y1);
2353c5ee0fc482e93912b9b090d0df1af496288a702John Reck        src_image->get_scanline(src_image, (void**)(&src2), y2);
2363c5ee0fc482e93912b9b090d0df1af496288a702John Reck        if (left_pad > 0) {
2373c5ee0fc482e93912b9b090d0df1af496288a702John Reck            buf1[0] = buf1[1] = 0;
2383c5ee0fc482e93912b9b090d0df1af496288a702John Reck            buf2[0] = buf2[1] = 0;
2395e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck            pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon(
2405e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    dst, buf1, buf2, weight1, weight2, 0, 0, left_pad);
2413c5ee0fc482e93912b9b090d0df1af496288a702John Reck            dst += left_pad;
2423c5ee0fc482e93912b9b090d0df1af496288a702John Reck        }
2433c5ee0fc482e93912b9b090d0df1af496288a702John Reck        if (left_tz > 0) {
2443c5ee0fc482e93912b9b090d0df1af496288a702John Reck            buf1[0] = 0;
2453c5ee0fc482e93912b9b090d0df1af496288a702John Reck            buf1[1] = src1[0];
2463c5ee0fc482e93912b9b090d0df1af496288a702John Reck            buf2[0] = 0;
2473c5ee0fc482e93912b9b090d0df1af496288a702John Reck            buf2[1] = src2[0];
2485e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck            pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon(
2495e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    dst, buf1, buf2, weight1, weight2,
2505e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    pixman_fixed_frac(vx), unit_x, left_tz);
2513c5ee0fc482e93912b9b090d0df1af496288a702John Reck            dst += left_tz;
2523c5ee0fc482e93912b9b090d0df1af496288a702John Reck            vx += left_tz * unit_x;
2533c5ee0fc482e93912b9b090d0df1af496288a702John Reck        }
2543c5ee0fc482e93912b9b090d0df1af496288a702John Reck        if (width > 0) {
2555e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck            pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon(
2565e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    dst, src1, src2, weight1, weight2, vx, unit_x, width);
2573c5ee0fc482e93912b9b090d0df1af496288a702John Reck            dst += width;
2583c5ee0fc482e93912b9b090d0df1af496288a702John Reck            vx += width * unit_x;
2593c5ee0fc482e93912b9b090d0df1af496288a702John Reck        }
2603c5ee0fc482e93912b9b090d0df1af496288a702John Reck        if (right_tz > 0) {
2613c5ee0fc482e93912b9b090d0df1af496288a702John Reck            buf1[0] = src1[src_width - 1];
2623c5ee0fc482e93912b9b090d0df1af496288a702John Reck            buf1[1] = 0;
2633c5ee0fc482e93912b9b090d0df1af496288a702John Reck            buf2[0] = src2[src_width - 1];
2643c5ee0fc482e93912b9b090d0df1af496288a702John Reck            buf2[1] = 0;
2655e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck            pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon(
2665e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    dst, buf1, buf2, weight1, weight2,
2675e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    pixman_fixed_frac(vx), unit_x, right_tz);
2683c5ee0fc482e93912b9b090d0df1af496288a702John Reck            dst += right_tz;
2693c5ee0fc482e93912b9b090d0df1af496288a702John Reck        }
2703c5ee0fc482e93912b9b090d0df1af496288a702John Reck        if (right_pad > 0) {
2713c5ee0fc482e93912b9b090d0df1af496288a702John Reck            buf1[0] = buf1[1] = 0;
2723c5ee0fc482e93912b9b090d0df1af496288a702John Reck            buf2[0] = buf2[1] = 0;
2735e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck            pixman_scaled_bilinear_scanline_8888_8888_SRC_asm_neon(
2745e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    dst, buf1, buf2, weight1, weight2, 0, 0, right_pad);
2755e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        }
2765e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    }
2775e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck}
2785e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck#endif // ARM_USE_NEON
2795e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck
2805e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reckstatic void android_nearest_filter(android_simple_image* src_image,
2815e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        android_simple_image* dst_image, float scale, int src_x, int src_y) {
2825e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    int32_t src_width = src_image->width;
2835e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    int32_t src_height = src_image->height;
2845e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    int32_t width = dst_image->width;
2855e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    int32_t height = dst_image->height;
2865e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    uint32_t dst_line = 0;
2875e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    int y;
2885e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    pixman_fixed_t src_width_fixed = pixman_int_to_fixed(src_width);
2895e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    pixman_fixed_t max_vy;
2905e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    pixman_vector_t v;
2915e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    pixman_fixed_t vx, vy;
2925e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    pixman_fixed_t unit_x, unit_y;
2935e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    int32_t left_pad, right_pad;
2945e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    uint32_t *src;
2955e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    uint32_t *dst;
2965e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    /* reference point is the center of the pixel */
2975e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    v.vector[0] = pixman_double_to_fixed((src_x + 0.5f) * scale);
2985e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    v.vector[1] = pixman_double_to_fixed((src_y + 0.5f) * scale);
2995e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    v.vector[2] = pixman_fixed_1;
3005e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    unit_x = unit_y = pixman_double_to_fixed(scale);
3015e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    vx = v.vector[0];
3025e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    vy = v.vector[1];
3035e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    pad_repeat_get_scanline_bounds(src_width, vx, unit_x,
3045e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck            &width, &left_pad, &right_pad);
3055e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    vx += left_pad * unit_x;
3065e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    while (--height >= 0) {
3075e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        dst_image->get_scanline(dst_image, (void**)(&dst), dst_line);
3085e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        dst_line++;
3095e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        y = ((int) ((vy) >> 16));
3105e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        vy += unit_y;
3115e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        static const uint32_t zero[1] = { 0 };
3125e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        if (y < 0 || y >= src_height) {
3135e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck            scaled_nearest_scanline_8888_8888_none_SRC(
3145e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    dst, zero + 1, left_pad + width + right_pad,
3155e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    -((pixman_fixed_t) 1), 0, src_width_fixed);
3165e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck            continue;
3173c5ee0fc482e93912b9b090d0df1af496288a702John Reck        }
3185e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        src_image->get_scanline(src_image, (void**)(&src), y);
3195e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        if (left_pad > 0) {
3205e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck            scaled_nearest_scanline_8888_8888_none_SRC(
3215e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    dst, zero + 1, left_pad, -((pixman_fixed_t) 1), 0,
3225e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    src_width_fixed);
3235e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        }
3245e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        if (width > 0) {
3255e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck            scaled_nearest_scanline_8888_8888_none_SRC(
3265e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    dst + left_pad, src + src_width, width,
3275e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    vx - src_width_fixed, unit_x, src_width_fixed);
3285e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        }
3295e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        if (right_pad > 0) {
3305e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck            scaled_nearest_scanline_8888_8888_none_SRC(
3315e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    dst + left_pad + width, zero + 1, right_pad,
3325e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck                    -((pixman_fixed_t) 1), 0, src_width_fixed);
3335e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        }
3345e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    }
3355e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck}
3365e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck
3375e97fcc235901c1018da86118c427d84d9f6a0dcJohn ReckPIXMAN_EXPORT void android_simple_scale(android_simple_image* src_image,
3385e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        android_simple_image* dst_image, float scale, int src_x, int src_y) {
3395e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck#ifdef USE_ARM_NEON
3405e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    if (android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM
3415e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck            && (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON)) {
3425e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        android_bilinear_filter_neon(src_image, dst_image, scale, src_x, src_y);
3435e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck        return;
3443c5ee0fc482e93912b9b090d0df1af496288a702John Reck    }
3455e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck#endif
3465e97fcc235901c1018da86118c427d84d9f6a0dcJohn Reck    android_nearest_filter(src_image, dst_image, scale, src_x, src_y);
3473c5ee0fc482e93912b9b090d0df1af496288a702John Reck}
348