зеркало из https://github.com/mozilla/moz-skia.git
add neon opts for matrix procs
git-svn-id: http://skia.googlecode.com/svn/trunk@353 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
ebdeeb8a01
Коммит
ed881c2704
|
@ -256,11 +256,16 @@ public:
|
|||
/** Styles apply to rect, oval, path, and text.
|
||||
Bitmaps are always drawn in "fill", and lines are always drawn in
|
||||
"stroke".
|
||||
|
||||
Note: strokeandfill implicitly draws the result with
|
||||
SkPath::kWinding_FillType, so if the original path is even-odd, the
|
||||
results may not appear the same as if it was drawn twice, filled and
|
||||
then stroked.
|
||||
*/
|
||||
enum Style {
|
||||
kFill_Style, //!< fill with the paint's color
|
||||
kStroke_Style, //!< stroke with the paint's color
|
||||
kStrokeAndFill_Style, //!< fill and stroke with the paint's color
|
||||
kFill_Style, //!< fill the geometry
|
||||
kStroke_Style, //!< stroke the geometry
|
||||
kStrokeAndFill_Style, //!< fill and stroke the geometry
|
||||
|
||||
kStyleCount,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
#include "SampleCode.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkParsePath.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRandom.h"
|
||||
#include "SkView.h"
|
||||
|
||||
static void scale_to_width(SkPath* path, SkScalar dstWidth) {
|
||||
const SkRect& bounds = path->getBounds();
|
||||
SkScalar scale = dstWidth / bounds.width();
|
||||
SkMatrix matrix;
|
||||
|
||||
matrix.setScale(scale, scale);
|
||||
path->transform(matrix);
|
||||
}
|
||||
|
||||
static const struct {
|
||||
SkPaint::Style fStyle;
|
||||
SkPaint::Join fJoin;
|
||||
int fStrokeWidth;
|
||||
} gRec[] = {
|
||||
{ SkPaint::kFill_Style, SkPaint::kMiter_Join, 0 },
|
||||
{ SkPaint::kStroke_Style, SkPaint::kMiter_Join, 0 },
|
||||
{ SkPaint::kStroke_Style, SkPaint::kMiter_Join, 10 },
|
||||
{ SkPaint::kStrokeAndFill_Style, SkPaint::kMiter_Join, 10 },
|
||||
};
|
||||
|
||||
class StrokePathView : public SkView {
|
||||
SkScalar fWidth;
|
||||
SkPath fPath;
|
||||
public:
|
||||
StrokePathView() {
|
||||
fWidth = SkIntToScalar(120);
|
||||
|
||||
#if 0
|
||||
const char str[] =
|
||||
"M 0, 3"
|
||||
"C 10, -10, 30, -10, 0, 28"
|
||||
"C -30, -10, -10, -10, 0, 3"
|
||||
"Z";
|
||||
SkParsePath::FromSVGString(str, &fPath);
|
||||
#else
|
||||
fPath.addCircle(0, 0, SkIntToScalar(50), SkPath::kCW_Direction);
|
||||
fPath.addCircle(0, SkIntToScalar(-50), SkIntToScalar(30), SkPath::kCW_Direction);
|
||||
#endif
|
||||
|
||||
scale_to_width(&fPath, fWidth);
|
||||
const SkRect& bounds = fPath.getBounds();
|
||||
fPath.offset(-bounds.fLeft, -bounds.fTop);
|
||||
}
|
||||
|
||||
protected:
|
||||
// overrides from SkEventSink
|
||||
virtual bool onQuery(SkEvent* evt) {
|
||||
if (SampleCode::TitleQ(*evt)) {
|
||||
SampleCode::TitleR(evt, "StrokePath");
|
||||
return true;
|
||||
}
|
||||
return this->INHERITED::onQuery(evt);
|
||||
}
|
||||
|
||||
void drawBG(SkCanvas* canvas) {
|
||||
canvas->drawColor(0xFFDDDDDD);
|
||||
}
|
||||
|
||||
SkRandom rand;
|
||||
|
||||
void drawSet(SkCanvas* canvas, SkPaint* paint) {
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
|
||||
paint->setStyle(gRec[i].fStyle);
|
||||
paint->setStrokeJoin(gRec[i].fJoin);
|
||||
paint->setStrokeWidth(SkIntToScalar(gRec[i].fStrokeWidth));
|
||||
canvas->drawPath(fPath, *paint);
|
||||
canvas->translate(fWidth * 5 / 4, 0);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
drawBG(canvas);
|
||||
canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(SK_ColorBLUE);
|
||||
|
||||
#if 1
|
||||
SkPath p;
|
||||
float r = rand.nextUScalar1() + 0.5f;
|
||||
SkScalar x = 0, y = 0;
|
||||
p.moveTo(x, y);
|
||||
#if 0
|
||||
p.cubicTo(x-75*r, y+75*r, x-40*r, y+125*r, x, y+85*r);
|
||||
p.cubicTo(x+40*r, y+125*r, x+75*r, y+75*r, x, y);
|
||||
#else
|
||||
p.cubicTo(x+75*r, y+75*r, x+40*r, y+125*r, x, y+85*r);
|
||||
p.cubicTo(x-40*r, y+125*r, x-75*r, y+75*r, x, y);
|
||||
#endif
|
||||
p.close();
|
||||
fPath = p;
|
||||
fPath.offset(100, 0);
|
||||
#endif
|
||||
|
||||
fPath.setFillType(SkPath::kWinding_FillType);
|
||||
drawSet(canvas, &paint);
|
||||
|
||||
canvas->translate(0, fPath.getBounds().height() * 5 / 4);
|
||||
fPath.setFillType(SkPath::kEvenOdd_FillType);
|
||||
drawSet(canvas, &paint);
|
||||
}
|
||||
|
||||
virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
|
||||
this->inval(NULL);
|
||||
return this->INHERITED::onFindClickHandler(x, y);
|
||||
}
|
||||
private:
|
||||
typedef SkView INHERITED;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static SkView* MyFactory() { return new StrokePathView; }
|
||||
static SkViewRegister reg(MyFactory);
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
/* NEON optimized code (C) COPYRIGHT 2009 Motorola */
|
||||
|
||||
#include "SkBitmapProcState.h"
|
||||
#include "SkPerspIter.h"
|
||||
#include "SkShader.h"
|
||||
|
@ -31,14 +33,22 @@ void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count);
|
|||
#define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF)
|
||||
#define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF)
|
||||
#define CHECK_FOR_DECAL
|
||||
#include "SkBitmapProcState_matrix.h"
|
||||
#if defined(__ARM_HAVE_NEON)
|
||||
#include "SkBitmapProcState_matrix_clamp.h"
|
||||
#else
|
||||
#include "SkBitmapProcState_matrix.h"
|
||||
#endif
|
||||
|
||||
#define MAKENAME(suffix) RepeatX_RepeatY ## suffix
|
||||
#define TILEX_PROCF(fx, max) (((fx) & 0xFFFF) * ((max) + 1) >> 16)
|
||||
#define TILEY_PROCF(fy, max) (((fy) & 0xFFFF) * ((max) + 1) >> 16)
|
||||
#define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
|
||||
#define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
|
||||
#include "SkBitmapProcState_matrix.h"
|
||||
#if defined(__ARM_HAVE_NEON)
|
||||
#include "SkBitmapProcState_matrix_repeat.h"
|
||||
#else
|
||||
#include "SkBitmapProcState_matrix.h"
|
||||
#endif
|
||||
|
||||
#define MAKENAME(suffix) GeneralXY ## suffix
|
||||
#define PREAMBLE(state) SkBitmapProcState::FixedTileProc tileProcX = (state).fTileProcX; \
|
||||
|
@ -147,6 +157,52 @@ void decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count)
|
|||
{
|
||||
int i;
|
||||
|
||||
#if defined(__ARM_HAVE_NEON)
|
||||
if (count >= 8) {
|
||||
/* SkFixed is 16.16 fixed point */
|
||||
SkFixed dx2 = dx+dx;
|
||||
SkFixed dx4 = dx2+dx2;
|
||||
SkFixed dx8 = dx4+dx4;
|
||||
|
||||
/* now build fx/fx+dx/fx+2dx/fx+3dx */
|
||||
SkFixed fx1, fx2, fx3;
|
||||
int32x2_t lower, upper;
|
||||
int32x4_t lbase, hbase;
|
||||
uint16_t *dst16 = (uint16_t *)dst;
|
||||
|
||||
fx1 = fx+dx;
|
||||
fx2 = fx1+dx;
|
||||
fx3 = fx2+dx;
|
||||
|
||||
/* avoid an 'lbase unitialized' warning */
|
||||
lbase = vdupq_n_s32(fx);
|
||||
lbase = vsetq_lane_s32(fx1, lbase, 1);
|
||||
lbase = vsetq_lane_s32(fx2, lbase, 2);
|
||||
lbase = vsetq_lane_s32(fx3, lbase, 3);
|
||||
hbase = vaddq_s32(lbase, vdupq_n_s32(dx4));
|
||||
|
||||
/* take upper 16 of each, store, and bump everything */
|
||||
do {
|
||||
int32x4_t lout, hout;
|
||||
uint16x8_t hi16;
|
||||
|
||||
lout = lbase;
|
||||
hout = hbase;
|
||||
/* gets hi's of all louts then hi's of all houts */
|
||||
asm ("vuzpq.16 %q0, %q1" : "+w" (lout), "+w" (hout));
|
||||
hi16 = vreinterpretq_u16_s32(hout);
|
||||
vst1q_u16(dst16, hi16);
|
||||
|
||||
/* on to the next */
|
||||
lbase = vaddq_s32 (lbase, vdupq_n_s32(dx8));
|
||||
hbase = vaddq_s32 (hbase, vdupq_n_s32(dx8));
|
||||
dst16 += 8;
|
||||
count -= 8;
|
||||
fx += dx8;
|
||||
} while (count >= 8);
|
||||
dst = (uint32_t *) dst16;
|
||||
}
|
||||
#else
|
||||
for (i = (count >> 2); i > 0; --i)
|
||||
{
|
||||
*dst++ = pack_two_shorts(fx >> 16, (fx + dx) >> 16);
|
||||
|
@ -154,16 +210,55 @@ void decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count)
|
|||
*dst++ = pack_two_shorts(fx >> 16, (fx + dx) >> 16);
|
||||
fx += dx+dx;
|
||||
}
|
||||
uint16_t* xx = (uint16_t*)dst;
|
||||
count &= 3;
|
||||
#endif
|
||||
|
||||
for (i = (count & 3); i > 0; --i)
|
||||
{
|
||||
uint16_t* xx = (uint16_t*)dst;
|
||||
for (i = count; i > 0; --i) {
|
||||
*xx++ = SkToU16(fx >> 16); fx += dx;
|
||||
}
|
||||
}
|
||||
|
||||
void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count)
|
||||
{
|
||||
|
||||
#if defined(__ARM_HAVE_NEON)
|
||||
if (count >= 8) {
|
||||
int32x4_t wide_fx;
|
||||
int32x4_t wide_fx2;
|
||||
int32x4_t wide_dx8 = vdupq_n_s32(dx*8);
|
||||
|
||||
wide_fx = vdupq_n_s32(fx);
|
||||
wide_fx = vsetq_lane_s32(fx+dx, wide_fx, 1);
|
||||
wide_fx = vsetq_lane_s32(fx+dx+dx, wide_fx, 2);
|
||||
wide_fx = vsetq_lane_s32(fx+dx+dx+dx, wide_fx, 3);
|
||||
|
||||
wide_fx2 = vaddq_s32(wide_fx, vdupq_n_s32(dx+dx+dx+dx));
|
||||
|
||||
while (count >= 8) {
|
||||
int32x4_t wide_out;
|
||||
int32x4_t wide_out2;
|
||||
|
||||
wide_out = vshlq_n_s32(vshrq_n_s32(wide_fx, 12), 14);
|
||||
wide_out = vorrq_s32(wide_out,
|
||||
vaddq_s32(vshrq_n_s32(wide_fx,16), vdupq_n_s32(1)));
|
||||
|
||||
wide_out2 = vshlq_n_s32(vshrq_n_s32(wide_fx2, 12), 14);
|
||||
wide_out2 = vorrq_s32(wide_out2,
|
||||
vaddq_s32(vshrq_n_s32(wide_fx2,16), vdupq_n_s32(1)));
|
||||
|
||||
vst1q_u32(dst, vreinterpretq_u32_s32(wide_out));
|
||||
vst1q_u32(dst+4, vreinterpretq_u32_s32(wide_out2));
|
||||
|
||||
dst += 8;
|
||||
fx += dx*8;
|
||||
wide_fx = vaddq_s32(wide_fx, wide_dx8);
|
||||
wide_fx2 = vaddq_s32(wide_fx2, wide_dx8);
|
||||
count -= 8;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (count & 1)
|
||||
{
|
||||
SkASSERT((fx >> (16 + 14)) == 0);
|
||||
|
|
|
@ -0,0 +1,826 @@
|
|||
/* NEON optimized code (C) COPYRIGHT 2009 Motorola */
|
||||
/*
|
||||
* Modifications done in-house at Motorola
|
||||
*
|
||||
* this is a clone of SkBitmapProcState_matrix.h
|
||||
* and has been tuned to work with the NEON unit.
|
||||
*
|
||||
* Still going back and forth between whether this approach
|
||||
* (clone the entire SkBitmapProcState_matrix.h file or
|
||||
* if I should put just the modified routines in here and
|
||||
* then use a construct like #define DONT_DO_THIS_FUNCTION or
|
||||
* something like that...
|
||||
*
|
||||
* This is for the ClampX_ClampY instance
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#if !defined(__ARM_HAVE_NEON)
|
||||
#error this file can be used only when the NEON unit is enabled
|
||||
#endif
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
/*
|
||||
* This has been modified on the knowledge that (at the time)
|
||||
* we had the following macro definitions in the parent file
|
||||
*
|
||||
* #define MAKENAME(suffix) ClampX_ClampY ## suffix
|
||||
* #define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max)
|
||||
* #define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max)
|
||||
* #define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF)
|
||||
* #define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF)
|
||||
* #define CHECK_FOR_DECAL
|
||||
*/
|
||||
|
||||
/* SkClampMax(val,max) -- bound to 0..max */
|
||||
|
||||
#define SCALE_NOFILTER_NAME MAKENAME(_nofilter_scale)
|
||||
#define SCALE_FILTER_NAME MAKENAME(_filter_scale)
|
||||
#define AFFINE_NOFILTER_NAME MAKENAME(_nofilter_affine)
|
||||
#define AFFINE_FILTER_NAME MAKENAME(_filter_affine)
|
||||
#define PERSP_NOFILTER_NAME MAKENAME(_nofilter_persp)
|
||||
#define PERSP_FILTER_NAME MAKENAME(_filter_persp)
|
||||
|
||||
#define PACK_FILTER_X_NAME MAKENAME(_pack_filter_x)
|
||||
#define PACK_FILTER_Y_NAME MAKENAME(_pack_filter_y)
|
||||
|
||||
#ifndef PREAMBLE
|
||||
#define PREAMBLE(state)
|
||||
#define PREAMBLE_PARAM_X
|
||||
#define PREAMBLE_PARAM_Y
|
||||
#define PREAMBLE_ARG_X
|
||||
#define PREAMBLE_ARG_Y
|
||||
#endif
|
||||
|
||||
static void SCALE_NOFILTER_NAME(const SkBitmapProcState& s,
|
||||
uint32_t xy[], int count, int x, int y) {
|
||||
SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
|
||||
SkMatrix::kScale_Mask)) == 0);
|
||||
|
||||
PREAMBLE(s);
|
||||
// we store y, x, x, x, x, x
|
||||
|
||||
const unsigned maxX = s.fBitmap->width() - 1;
|
||||
SkFixed fx;
|
||||
{
|
||||
SkPoint pt;
|
||||
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, &pt);
|
||||
fx = SkScalarToFixed(pt.fY);
|
||||
const unsigned maxY = s.fBitmap->height() - 1;
|
||||
*xy++ = TILEY_PROCF(fx, maxY);
|
||||
fx = SkScalarToFixed(pt.fX);
|
||||
}
|
||||
|
||||
if (0 == maxX) {
|
||||
// all of the following X values must be 0
|
||||
memset(xy, 0, count * sizeof(uint16_t));
|
||||
return;
|
||||
}
|
||||
|
||||
const SkFixed dx = s.fInvSx;
|
||||
|
||||
#ifdef CHECK_FOR_DECAL
|
||||
// test if we don't need to apply the tile proc
|
||||
if ((unsigned)(fx >> 16) <= maxX &&
|
||||
(unsigned)((fx + dx * (count - 1)) >> 16) <= maxX) {
|
||||
decal_nofilter_scale(xy, fx, dx, count);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int i;
|
||||
|
||||
/* very much like done in decal_nofilter, but with
|
||||
* an extra clamping function applied.
|
||||
* TILEX_PROCF(fx,max) SkClampMax((fx)>>16, max)
|
||||
*/
|
||||
if (count >= 8) {
|
||||
/* SkFixed is 16.16 fixed point */
|
||||
SkFixed dx2 = dx+dx;
|
||||
SkFixed dx4 = dx2+dx2;
|
||||
SkFixed dx8 = dx4+dx4;
|
||||
|
||||
/* now build fx/fx+dx/fx+2dx/fx+3dx */
|
||||
SkFixed fx1, fx2, fx3;
|
||||
int32x2_t lower, upper;
|
||||
int32x4_t lbase, hbase;
|
||||
int16_t *dst16 = (int16_t *)xy;
|
||||
|
||||
fx1 = fx+dx;
|
||||
fx2 = fx1+dx;
|
||||
fx3 = fx2+dx;
|
||||
|
||||
/* build my template(s) */
|
||||
/* avoid the 'lbase unitialized' warning */
|
||||
lbase = vdupq_n_s32(fx);
|
||||
lbase = vsetq_lane_s32(fx1, lbase, 1);
|
||||
lbase = vsetq_lane_s32(fx2, lbase, 2);
|
||||
lbase = vsetq_lane_s32(fx3, lbase, 3);
|
||||
|
||||
hbase = vaddq_s32(lbase, vdupq_n_s32(dx4));
|
||||
|
||||
/* store & bump */
|
||||
do {
|
||||
int32x4_t lout;
|
||||
int32x4_t hout;
|
||||
int16x8_t hi16;
|
||||
|
||||
/* get the hi 16s of all those 32s */
|
||||
lout = lbase;
|
||||
hout = hbase;
|
||||
/* this sets up all lout's then all hout's in hout */
|
||||
asm ("vuzpq.16 %q0, %q1" : "+w" (lout), "+w" (hout));
|
||||
hi16 = vreinterpretq_s16_s32(hout);
|
||||
|
||||
/* clamp & output */
|
||||
hi16 = vmaxq_s16(hi16, vdupq_n_s16(0));
|
||||
hi16 = vminq_s16(hi16, vdupq_n_s16(maxX));
|
||||
vst1q_s16(dst16, hi16);
|
||||
|
||||
/* but preserving base & on to the next */
|
||||
lbase = vaddq_s32 (lbase, vdupq_n_s32(dx8));
|
||||
hbase = vaddq_s32 (hbase, vdupq_n_s32(dx8));
|
||||
dst16 += 8;
|
||||
count -= 8;
|
||||
fx += dx8;
|
||||
} while (count >= 8);
|
||||
xy = (uint32_t *) dst16;
|
||||
}
|
||||
|
||||
uint16_t* xx = (uint16_t*)xy;
|
||||
for (i = count; i > 0; --i) {
|
||||
*xx++ = TILEX_PROCF(fx, maxX); fx += dx;
|
||||
}
|
||||
}
|
||||
|
||||
// note: we could special-case on a matrix which is skewed in X but not Y.
|
||||
// this would require a more general setup thatn SCALE does, but could use
|
||||
// SCALE's inner loop that only looks at dx
|
||||
|
||||
static void AFFINE_NOFILTER_NAME(const SkBitmapProcState& s,
|
||||
uint32_t xy[], int count, int x, int y) {
|
||||
SkASSERT(s.fInvType & SkMatrix::kAffine_Mask);
|
||||
SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
|
||||
SkMatrix::kScale_Mask |
|
||||
SkMatrix::kAffine_Mask)) == 0);
|
||||
|
||||
PREAMBLE(s);
|
||||
SkPoint srcPt;
|
||||
s.fInvProc(*s.fInvMatrix,
|
||||
SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
|
||||
|
||||
SkFixed fx = SkScalarToFixed(srcPt.fX);
|
||||
SkFixed fy = SkScalarToFixed(srcPt.fY);
|
||||
SkFixed dx = s.fInvSx;
|
||||
SkFixed dy = s.fInvKy;
|
||||
int maxX = s.fBitmap->width() - 1;
|
||||
int maxY = s.fBitmap->height() - 1;
|
||||
|
||||
/* NEON lets us do an 8x unrolling */
|
||||
if (count >= 8) {
|
||||
/* SkFixed is 16.16 fixed point */
|
||||
SkFixed dx4 = dx * 4;
|
||||
SkFixed dy4 = dy * 4;
|
||||
SkFixed dx8 = dx * 8;
|
||||
SkFixed dy8 = dy * 8;
|
||||
|
||||
int32x4_t xbase, ybase;
|
||||
int32x4_t x2base, y2base;
|
||||
int16_t *dst16 = (int16_t *) xy;
|
||||
|
||||
/* my sets of maxx/maxy for clamping */
|
||||
int32_t maxpair = (maxX&0xffff) | ((maxY&0xffff)<<16);
|
||||
int16x8_t maxXY = vreinterpretq_s16_s32(vdupq_n_s32(maxpair));
|
||||
|
||||
/* now build fx/fx+dx/fx+2dx/fx+3dx */
|
||||
/* avoid the 'xbase unitialized' warning...*/
|
||||
xbase = vdupq_n_s32(fx);
|
||||
xbase = vsetq_lane_s32(fx+dx, xbase, 1);
|
||||
xbase = vsetq_lane_s32(fx+dx+dx, xbase, 2);
|
||||
xbase = vsetq_lane_s32(fx+dx+dx+dx, xbase, 3);
|
||||
|
||||
/* same for fy */
|
||||
/* avoid the 'ybase unitialized' warning...*/
|
||||
ybase = vdupq_n_s32(fy);
|
||||
ybase = vsetq_lane_s32(fy+dy, ybase, 1);
|
||||
ybase = vsetq_lane_s32(fy+dy+dy, ybase, 2);
|
||||
ybase = vsetq_lane_s32(fy+dy+dy+dy, ybase, 3);
|
||||
|
||||
x2base = vaddq_s32(xbase, vdupq_n_s32(dx4));
|
||||
y2base = vaddq_s32(ybase, vdupq_n_s32(dy4));
|
||||
|
||||
/* store & bump */
|
||||
do {
|
||||
int32x4_t xout, yout;
|
||||
int32x4_t x2out, y2out;
|
||||
int16x8_t hi16, hi16_2;
|
||||
|
||||
xout = xbase;
|
||||
yout = ybase;
|
||||
|
||||
/* overlay y's low16 with hi16 from x */
|
||||
/* so we properly shifted xyxyxyxy */
|
||||
yout = vsriq_n_s32(yout, xout, 16);
|
||||
hi16 = vreinterpretq_s16_s32 (yout);
|
||||
|
||||
/* do the clamping; both guys get 0's */
|
||||
hi16 = vmaxq_s16 (hi16, vdupq_n_s16(0));
|
||||
hi16 = vminq_s16 (hi16, maxXY);
|
||||
|
||||
vst1q_s16 (dst16, hi16);
|
||||
|
||||
/* and for the other 4 pieces of this iteration */
|
||||
x2out = x2base;
|
||||
y2out = y2base;
|
||||
|
||||
/* overlay y's low16 with hi16 from x */
|
||||
/* so we properly shifted xyxyxyxy */
|
||||
y2out = vsriq_n_s32(y2out, x2out, 16);
|
||||
hi16_2 = vreinterpretq_s16_s32 (y2out);
|
||||
|
||||
/* do the clamping; both guys get 0's */
|
||||
hi16_2 = vmaxq_s16 (hi16_2, vdupq_n_s16(0));
|
||||
hi16_2 = vminq_s16 (hi16_2, maxXY);
|
||||
|
||||
/* RBE: gcc regenerates dst16+8 all the time instead
|
||||
* of folding it into an addressing mode. *sigh* */
|
||||
vst1q_s16 (dst16+8, hi16_2);
|
||||
|
||||
/* moving base and on to the next */
|
||||
xbase = vaddq_s32 (xbase, vdupq_n_s32 (dx8));
|
||||
ybase = vaddq_s32 (ybase, vdupq_n_s32 (dy8));
|
||||
x2base = vaddq_s32 (x2base, vdupq_n_s32 (dx8));
|
||||
y2base = vaddq_s32 (y2base, vdupq_n_s32 (dy8));
|
||||
|
||||
dst16 += 16; /* 8x32 aka 16x16 */
|
||||
count -= 8;
|
||||
fx += dx8;
|
||||
fy += dy8;
|
||||
} while (count >= 8);
|
||||
xy = (uint32_t *) dst16;
|
||||
}
|
||||
|
||||
for (int i = count; i > 0; --i) {
|
||||
*xy++ = (TILEY_PROCF(fy, maxY) << 16) | TILEX_PROCF(fx, maxX);
|
||||
fx += dx; fy += dy;
|
||||
}
|
||||
}
|
||||
|
||||
static void PERSP_NOFILTER_NAME(const SkBitmapProcState& s,
|
||||
uint32_t* SK_RESTRICT xy,
|
||||
int count, int x, int y) {
|
||||
SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask);
|
||||
|
||||
PREAMBLE(s);
|
||||
/* max{X,Y} are int here, but later shown/assumed to fit in 16 bits */
|
||||
int maxX = s.fBitmap->width() - 1;
|
||||
int maxY = s.fBitmap->height() - 1;
|
||||
|
||||
SkPerspIter iter(*s.fInvMatrix,
|
||||
SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, count);
|
||||
|
||||
while ((count = iter.next()) != 0) {
|
||||
const SkFixed* SK_RESTRICT srcXY = iter.getXY();
|
||||
|
||||
/* srcXY is a batch of 32 bit numbers X0,Y0,X1,Y1...
|
||||
* but we immediately discard the low 16 bits...
|
||||
* so what we're going to do is vld4, which will give us
|
||||
* xlo,xhi,ylo,yhi distribution and we can ignore the 'lo'
|
||||
* parts....
|
||||
*/
|
||||
if (count >= 8) {
|
||||
int16_t *mysrc = (int16_t *) srcXY;
|
||||
int16_t *mydst = (int16_t *) xy;
|
||||
int16x4_t maxX4 = vdup_n_s16((int16_t)maxX);
|
||||
int16x4_t maxY4 = vdup_n_s16((int16_t)maxY);
|
||||
int16x4_t zero4 = vdup_n_s16(0);
|
||||
do {
|
||||
register int16x4_t xlo asm("d0");
|
||||
register int16x4_t xhi asm("d1");
|
||||
register int16x4_t ylo asm("d2");
|
||||
register int16x4_t yhi asm("d3");
|
||||
register int16x4_t x2lo asm("d4");
|
||||
register int16x4_t x2hi asm("d5");
|
||||
register int16x4_t y2lo asm("d6");
|
||||
register int16x4_t y2hi asm("d7");
|
||||
|
||||
register int16x4_t out_xhi asm("d8");
|
||||
register int16x4_t out_yhi asm("d9");
|
||||
register int16x4_t out_x2hi asm("d10");
|
||||
register int16x4_t out_y2hi asm("d11");
|
||||
|
||||
|
||||
/* vld4 does the de-interleaving for us */
|
||||
/* dependent on register assignments above */
|
||||
asm ("vld4.16 {d0-d3},[%4] /* xlo=%P0 xhi=%P1 ylo=%P2 yhi=%P3 */"
|
||||
: "=w" (xlo), "=w" (xhi), "=w" (ylo), "=w" (yhi)
|
||||
: "r" (mysrc)
|
||||
);
|
||||
|
||||
/* offset == 256 bits == 32 bytes == 8 longs */
|
||||
asm ("vld4.16 {d4-d7},[%4,#32] /* xlo=%P0 xhi=%P1 ylo=%P2 yhi=%P3 */"
|
||||
: "=w" (x2lo), "=w" (x2hi), "=w" (y2lo), "=w" (y2hi)
|
||||
: "r" (mysrc)
|
||||
);
|
||||
|
||||
/* clamp the first 4 here */
|
||||
|
||||
/* clamp X>>16 (aka xhi) to 0..maxX */
|
||||
xhi = vmax_s16(xhi, zero4); /* now 0.. */
|
||||
out_xhi = vmin_s16(xhi, maxX4); /* now 0..maxX */
|
||||
|
||||
/* clamp Y>>16 (aka yhi) to 0..maxY */
|
||||
yhi = vmax_s16(yhi, zero4); /* now 0.. */
|
||||
out_yhi = vmin_s16(yhi, maxY4); /* now 0..maxY */
|
||||
|
||||
/* clamp the second 4 here */
|
||||
|
||||
/* clamp X>>16 (aka xhi) to 0..maxX */
|
||||
x2hi = vmax_s16(x2hi, zero4); /* now 0.. */
|
||||
out_x2hi = vmin_s16(x2hi, maxX4); /* now 0..maxX */
|
||||
|
||||
/* clamp Y>>16 (aka yhi) to 0..maxY */
|
||||
y2hi = vmax_s16(y2hi, zero4); /* now 0.. */
|
||||
out_y2hi = vmin_s16(y2hi, maxY4); /* now 0..maxY */
|
||||
|
||||
/* we're storing as {x,y}s: x is [0], y is [1] */
|
||||
/* we'll use vst2 to make this happen */
|
||||
/* XXX: could use auto increment! */
|
||||
asm ("vst2.16 {d8-d9},[%2] /* xlo=%P0 xhi=%P1 */"
|
||||
:
|
||||
: "w" (out_xhi), "w" (out_yhi), "r" (mydst)
|
||||
);
|
||||
|
||||
/* offset == 16 bytes == 8 shorts */
|
||||
asm ("vst2.16 {d10-d11},[%2,#16] /* xlo=%P0 xhi=%P1 */"
|
||||
:
|
||||
: "w" (out_x2hi), "w" (out_y2hi), "r" (mydst)
|
||||
);
|
||||
|
||||
/* XXX: gcc isn't interleaving these with the NEON ops
|
||||
* but i think that all the scoreboarding works out */
|
||||
count -= 8; /* 8 iterations */
|
||||
mysrc += 32; /* 16 longs, aka 32 shorts */
|
||||
mydst += 16; /* 16 shorts, aka 8 longs */
|
||||
} while (count >= 8);
|
||||
/* get xy and srcXY fixed up */
|
||||
srcXY = (const SkFixed *) mysrc;
|
||||
xy = (uint32_t *) mydst;
|
||||
}
|
||||
|
||||
while (--count >= 0) {
|
||||
*xy++ = (TILEY_PROCF(srcXY[1], maxY) << 16) |
|
||||
TILEX_PROCF(srcXY[0], maxX);
|
||||
srcXY += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline uint32_t PACK_FILTER_Y_NAME(SkFixed f, unsigned max,
|
||||
SkFixed one PREAMBLE_PARAM_Y) {
|
||||
unsigned i = TILEY_PROCF(f, max);
|
||||
i = (i << 4) | TILEY_LOW_BITS(f, max);
|
||||
return (i << 14) | (TILEY_PROCF((f + one), max));
|
||||
}
|
||||
|
||||
static inline uint32_t PACK_FILTER_X_NAME(SkFixed f, unsigned max,
|
||||
SkFixed one PREAMBLE_PARAM_X) {
|
||||
unsigned i = TILEX_PROCF(f, max);
|
||||
i = (i << 4) | TILEX_LOW_BITS(f, max);
|
||||
return (i << 14) | (TILEX_PROCF((f + one), max));
|
||||
}
|
||||
|
||||
static void SCALE_FILTER_NAME(const SkBitmapProcState& s,
|
||||
uint32_t xy[], int count, int x, int y) {
|
||||
SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
|
||||
SkMatrix::kScale_Mask)) == 0);
|
||||
SkASSERT(s.fInvKy == 0);
|
||||
|
||||
PREAMBLE(s);
|
||||
|
||||
const unsigned maxX = s.fBitmap->width() - 1;
|
||||
const SkFixed one = s.fFilterOneX;
|
||||
const SkFixed dx = s.fInvSx;
|
||||
SkFixed fx;
|
||||
|
||||
{
|
||||
SkPoint pt;
|
||||
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, &pt);
|
||||
const SkFixed fy = SkScalarToFixed(pt.fY) - (s.fFilterOneY >> 1);
|
||||
const unsigned maxY = s.fBitmap->height() - 1;
|
||||
// compute our two Y values up front
|
||||
*xy++ = PACK_FILTER_Y_NAME(fy, maxY, s.fFilterOneY PREAMBLE_ARG_Y);
|
||||
// now initialize fx
|
||||
fx = SkScalarToFixed(pt.fX) - (one >> 1);
|
||||
}
|
||||
|
||||
#ifdef CHECK_FOR_DECAL
|
||||
// test if we don't need to apply the tile proc
|
||||
if (dx > 0 &&
|
||||
(unsigned)(fx >> 16) <= maxX &&
|
||||
(unsigned)((fx + dx * (count - 1)) >> 16) < maxX) {
|
||||
decal_filter_scale(xy, fx, dx, count);
|
||||
} else
|
||||
#endif
|
||||
|
||||
if (count >= 4) {
|
||||
int32x4_t wide_dx, wide_one;
|
||||
int32x4_t wide_fx, wide_fx1, wide_i, wide_lo;
|
||||
#if 0
|
||||
/* verification hooks -- see below */
|
||||
SkFixed debug_fx = fx;
|
||||
int count_done = 0;
|
||||
#endif
|
||||
|
||||
wide_fx = vdupq_n_s32(fx);
|
||||
wide_fx = vsetq_lane_s32(fx+dx, wide_fx, 1);
|
||||
wide_fx = vsetq_lane_s32(fx+dx+dx, wide_fx, 2);
|
||||
wide_fx = vsetq_lane_s32(fx+dx+dx+dx, wide_fx, 3);
|
||||
|
||||
wide_dx = vdupq_n_s32(dx);
|
||||
wide_one = vdupq_n_s32(one);
|
||||
|
||||
while (count >= 4) {
|
||||
/* original expands to:
|
||||
* unsigned i = SkClampMax((f) >> 16, max);
|
||||
* i = (i << 4) | (((f) >> 12) & 0xF);
|
||||
* return (i << 14) | (SkClampMax(((f + one)) >> 16, max));
|
||||
*/
|
||||
|
||||
/* i = SkClampMax(f>>16, maxX) */
|
||||
wide_i = vmaxq_s32(vshrq_n_s32(wide_fx,16), vdupq_n_s32(0));
|
||||
wide_i = vminq_s32(wide_i, vdupq_n_s32(maxX));
|
||||
|
||||
/* i<<4 | TILEX_LOW_BITS(fx) */
|
||||
wide_lo = vshrq_n_s32(wide_fx, 12);
|
||||
wide_i = vsliq_n_s32(wide_lo, wide_i, 4);
|
||||
|
||||
/* i<<14 */
|
||||
wide_i = vshlq_n_s32(wide_i, 14);
|
||||
|
||||
/* SkClampMax(((f + one)) >> 16, max) */
|
||||
wide_fx1 = vaddq_s32(wide_fx, wide_one);
|
||||
wide_fx1 = vmaxq_s32(vshrq_n_s32(wide_fx1,16), vdupq_n_s32(0));
|
||||
wide_fx1 = vminq_s32(wide_fx1, vdupq_n_s32(maxX));
|
||||
|
||||
/* final combination */
|
||||
wide_i = vorrq_s32(wide_i, wide_fx1);
|
||||
|
||||
vst1q_u32(xy, vreinterpretq_u32_s32(wide_i));
|
||||
|
||||
#if 0
|
||||
/* having a verification hook is a good idea */
|
||||
/* use debug_fx, debug_fx+dx, etc. */
|
||||
|
||||
for (int i=0;i<4;i++) {
|
||||
uint32_t want = PACK_FILTER_X_NAME(debug_fx, maxX, one PREAMBLE_ARG_X);
|
||||
if (xy[i] != want)
|
||||
{
|
||||
/* print a nastygram */
|
||||
SkDebugf("clamp-filter-scale fails\n");
|
||||
SkDebugf("got %08x want %08x\n", xy[i], want);
|
||||
SkDebugf("fx %08x debug_fx %08x dx %08x done %d\n",
|
||||
fx, debug_fx, dx, count_done);
|
||||
SkDebugf(" maxX %08x one %08x\n", maxX, one);
|
||||
|
||||
}
|
||||
debug_fx += dx;
|
||||
count_done++;
|
||||
}
|
||||
#endif
|
||||
wide_fx += vdupq_n_s32(dx+dx+dx+dx);
|
||||
fx += dx+dx+dx+dx;
|
||||
xy += 4;
|
||||
count -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
while (--count >= 0) {
|
||||
*xy++ = PACK_FILTER_X_NAME(fx, maxX, one PREAMBLE_ARG_X);
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
|
||||
static void AFFINE_FILTER_NAME(const SkBitmapProcState& s,
|
||||
uint32_t xy[], int count, int x, int y) {
|
||||
SkASSERT(s.fInvType & SkMatrix::kAffine_Mask);
|
||||
SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
|
||||
SkMatrix::kScale_Mask |
|
||||
SkMatrix::kAffine_Mask)) == 0);
|
||||
|
||||
PREAMBLE(s);
|
||||
SkPoint srcPt;
|
||||
s.fInvProc(*s.fInvMatrix,
|
||||
SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
|
||||
|
||||
SkFixed oneX = s.fFilterOneX;
|
||||
SkFixed oneY = s.fFilterOneY;
|
||||
SkFixed fx = SkScalarToFixed(srcPt.fX) - (oneX >> 1);
|
||||
SkFixed fy = SkScalarToFixed(srcPt.fY) - (oneY >> 1);
|
||||
SkFixed dx = s.fInvSx;
|
||||
SkFixed dy = s.fInvKy;
|
||||
unsigned maxX = s.fBitmap->width() - 1;
|
||||
unsigned maxY = s.fBitmap->height() - 1;
|
||||
|
||||
if (count >= 4) {
|
||||
int32x4_t wide_one, wide_i, wide_lo;
|
||||
int32x4_t wide_dx, wide_fx, wide_onex, wide_fx1;
|
||||
int32x4_t wide_dy, wide_fy, wide_oney, wide_fy1;
|
||||
|
||||
/* need side-by-side registers for vst2.32 tricks */
|
||||
register int32x4_t wide_x asm("q1");
|
||||
register int32x4_t wide_y asm("q0");
|
||||
|
||||
#undef AFFINE_DEBUG
|
||||
#if defined(AFFINE_DEBUG)
|
||||
SkFixed fyp = fy;
|
||||
SkFixed fxp = fx;
|
||||
uint32_t *xyp = xy;
|
||||
int count_done = 0;
|
||||
#endif
|
||||
|
||||
wide_fx = vdupq_n_s32(fx);
|
||||
wide_fx = vsetq_lane_s32(fx+dx, wide_fx, 1);
|
||||
wide_fx = vsetq_lane_s32(fx+dx+dx, wide_fx, 2);
|
||||
wide_fx = vsetq_lane_s32(fx+dx+dx+dx, wide_fx, 3);
|
||||
wide_dx = vdupq_n_s32(dx);
|
||||
|
||||
wide_fy = vdupq_n_s32(fy);
|
||||
wide_fy = vsetq_lane_s32(fy+dy, wide_fy, 1);
|
||||
wide_fy = vsetq_lane_s32(fy+dy+dy, wide_fy, 2);
|
||||
wide_fy = vsetq_lane_s32(fy+dy+dy+dy, wide_fy, 3);
|
||||
wide_dy = vdupq_n_s32(dy);
|
||||
|
||||
wide_onex = vdupq_n_s32(oneX);
|
||||
wide_oney = vdupq_n_s32(oneY);
|
||||
|
||||
while (count >= 4) {
|
||||
/* do the X side, then the Y side, then interleave them */
|
||||
|
||||
/* original expands to:
|
||||
* unsigned i = SkClampMax((f) >> 16, max);
|
||||
* i = (i << 4) | (((f) >> 12) & 0xF);
|
||||
* return (i << 14) | (SkClampMax(((f + one)) >> 16, max));
|
||||
*/
|
||||
|
||||
/* i = SkClampMax(f>>16, maxX) */
|
||||
wide_i = vmaxq_s32(vshrq_n_s32(wide_fx,16), vdupq_n_s32(0));
|
||||
wide_i = vminq_s32(wide_i, vdupq_n_s32(maxX));
|
||||
|
||||
/* i<<4 | TILEX_LOW_BITS(fx) */
|
||||
wide_lo = vshrq_n_s32(wide_fx, 12);
|
||||
wide_i = vsliq_n_s32(wide_lo, wide_i, 4);
|
||||
|
||||
/* i<<14 */
|
||||
wide_i = vshlq_n_s32(wide_i, 14);
|
||||
|
||||
/* SkClampMax(((f + one)) >> 16, max) */
|
||||
wide_fx1 = vaddq_s32(wide_fx, wide_onex);
|
||||
wide_fx1 = vmaxq_s32(vshrq_n_s32(wide_fx1,16), vdupq_n_s32(0));
|
||||
wide_fx1 = vminq_s32(wide_fx1, vdupq_n_s32(maxX));
|
||||
|
||||
/* final combination */
|
||||
wide_x = vorrq_s32(wide_i, wide_fx1);
|
||||
|
||||
/* And now the Y side */
|
||||
|
||||
/* i = SkClampMax(f>>16, maxX) */
|
||||
wide_i = vmaxq_s32(vshrq_n_s32(wide_fy,16), vdupq_n_s32(0));
|
||||
wide_i = vminq_s32(wide_i, vdupq_n_s32(maxY));
|
||||
|
||||
/* i<<4 | TILEX_LOW_BITS(fx) */
|
||||
wide_lo = vshrq_n_s32(wide_fy, 12);
|
||||
wide_i = vsliq_n_s32(wide_lo, wide_i, 4);
|
||||
|
||||
/* i<<14 */
|
||||
wide_i = vshlq_n_s32(wide_i, 14);
|
||||
|
||||
/* SkClampMax(((f + one)) >> 16, max) */
|
||||
wide_fy1 = vaddq_s32(wide_fy, wide_oney);
|
||||
wide_fy1 = vmaxq_s32(vshrq_n_s32(wide_fy1,16), vdupq_n_s32(0));
|
||||
wide_fy1 = vminq_s32(wide_fy1, vdupq_n_s32(maxY));
|
||||
|
||||
/* final combination */
|
||||
wide_y = vorrq_s32(wide_i, wide_fy1);
|
||||
|
||||
/* interleave as YXYXYXYX as part of the storing */
|
||||
asm ("vst2.32 {q0-q1},[%2] /* y=%q0 x=%q1 */"
|
||||
:
|
||||
: "w" (wide_y), "w" (wide_x), "r" (xy)
|
||||
);
|
||||
|
||||
#if defined(AFFINE_DEBUG)
|
||||
/* make sure we're good here -- check the 4 we just output */
|
||||
for (int i = 0; i<4;i++) {
|
||||
uint32_t val;
|
||||
val = PACK_FILTER_Y_NAME(fyp, maxY, oneY PREAMBLE_ARG_Y);
|
||||
if (val != xy[i*2+0]) {
|
||||
/* print a nastygram */
|
||||
SkDebugf("clamp-filter-affine fails\n");
|
||||
SkDebugf("[bad-y] got %08x want %08x\n", xy[i*2+0], val);
|
||||
SkDebugf("fy %08x fxp %08x fyp %08x dx %08x dy %08x done %d\n",
|
||||
fy, fxp, fyp, dx, dy, count_done);
|
||||
SkDebugf(" maxY %08x oneY %08x\n", maxY, oneY);
|
||||
}
|
||||
val = PACK_FILTER_X_NAME(fxp, maxX, oneX PREAMBLE_ARG_X);
|
||||
if (val != xy[i*2+1]) {
|
||||
/* print a nastygram */
|
||||
SkDebugf("clamp-filter-affine fails\n");
|
||||
SkDebugf("[bad-x] got %08x want %08x\n", xy[i*2+1], val);
|
||||
SkDebugf("fx %08x fxp %08x fyp %08x dx %08x dy %08x done %d\n",
|
||||
fx, fxp, fyp, dx, dy, count_done);
|
||||
SkDebugf(" maxX %08x one %08x\n", maxX, oneX);
|
||||
}
|
||||
fyp += dy;
|
||||
fxp += dx;
|
||||
count_done++;
|
||||
}
|
||||
#endif
|
||||
|
||||
wide_fx += vdupq_n_s32(dx+dx+dx+dx);
|
||||
fx += dx+dx+dx+dx;
|
||||
wide_fy += vdupq_n_s32(dy+dy+dy+dy);
|
||||
fy += dy+dy+dy+dy;
|
||||
xy += 8; /* 4 x's, 4 y's */
|
||||
count -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
while (--count >= 0) {
|
||||
/* NB: writing Y/X */
|
||||
*xy++ = PACK_FILTER_Y_NAME(fy, maxY, oneY PREAMBLE_ARG_Y);
|
||||
fy += dy;
|
||||
*xy++ = PACK_FILTER_X_NAME(fx, maxX, oneX PREAMBLE_ARG_X);
|
||||
fx += dx;
|
||||
}
|
||||
}
|
||||
|
||||
static void PERSP_FILTER_NAME(const SkBitmapProcState& s,
|
||||
uint32_t* SK_RESTRICT xy, int count,
|
||||
int x, int y) {
|
||||
SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask);
|
||||
|
||||
PREAMBLE(s);
|
||||
unsigned maxX = s.fBitmap->width() - 1;
|
||||
unsigned maxY = s.fBitmap->height() - 1;
|
||||
SkFixed oneX = s.fFilterOneX;
|
||||
SkFixed oneY = s.fFilterOneY;
|
||||
|
||||
SkPerspIter iter(*s.fInvMatrix,
|
||||
SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, count);
|
||||
|
||||
while ((count = iter.next()) != 0) {
|
||||
const SkFixed* SK_RESTRICT srcXY = iter.getXY();
|
||||
|
||||
if (count >= 4) {
|
||||
int32x4_t wide_one, wide_i, wide_lo;
|
||||
int32x4_t wide_fx1;
|
||||
int32x4_t wide_fy1;
|
||||
int32x4_t wide_x, wide_y;
|
||||
|
||||
/* need side-by-side regs for vld2/vst2 tricks */
|
||||
register int32x4_t wide_first asm ("q0");
|
||||
register int32x4_t wide_second asm ("q1");
|
||||
|
||||
while (count >= 4) {
|
||||
/* RBE: it's good, but:
|
||||
* -- we spill a constant that could be easily regnerated
|
||||
* [perhaps tweak gcc's NEON constant costs?]
|
||||
*/
|
||||
|
||||
/* load src: x-y-x-y-x-y-x-y */
|
||||
asm ("vld2.32 {q0-q1},[%2] /* x=%q0 y=%q1 */"
|
||||
: "=w" (wide_first), "=w" (wide_second)
|
||||
: "r" (srcXY));
|
||||
|
||||
wide_x = wide_first;
|
||||
wide_y = wide_second;
|
||||
|
||||
/* do the X side, then the Y side, then interleave them */
|
||||
|
||||
wide_x = vsubq_s32(wide_x, vdupq_n_s32 (oneX>>1));
|
||||
|
||||
/* original expands to:
|
||||
* unsigned i = SkClampMax((f) >> 16, max);
|
||||
* i = (i << 4) | (((f) >> 12) & 0xF);
|
||||
* return (i << 14) | (SkClampMax(((f + one)) >> 16, max));
|
||||
*/
|
||||
|
||||
/* i = SkClampMax(f>>16, maxX) */
|
||||
wide_i = vmaxq_s32 (vshrq_n_s32 (wide_x, 16), vdupq_n_s32 (0));
|
||||
wide_i = vminq_s32 (wide_i, vdupq_n_s32 (maxX));
|
||||
|
||||
/* i<<4 | TILEX_LOW_BITS(fx) */
|
||||
wide_lo = vshrq_n_s32 (wide_x, 12);
|
||||
wide_i = vsliq_n_s32 (wide_lo, wide_i, 4);
|
||||
|
||||
/* i<<14 */
|
||||
wide_i = vshlq_n_s32 (wide_i, 14);
|
||||
|
||||
/* SkClampMax(((f + one)) >> 16, max) */
|
||||
wide_fx1 = vaddq_s32 (wide_x, vdupq_n_s32(oneX));
|
||||
wide_fx1 = vmaxq_s32 (vshrq_n_s32 (wide_fx1, 16), vdupq_n_s32 (0));
|
||||
wide_fx1 = vminq_s32 (wide_fx1, vdupq_n_s32 (maxX));
|
||||
|
||||
/* final combination */
|
||||
wide_x = vorrq_s32 (wide_i, wide_fx1);
|
||||
|
||||
|
||||
/* And now the Y side */
|
||||
|
||||
wide_y = vsubq_s32(wide_y, vdupq_n_s32 (oneY>>1));
|
||||
|
||||
/* i = SkClampMax(f>>16, maxX) */
|
||||
wide_i = vmaxq_s32 (vshrq_n_s32 (wide_y, 16), vdupq_n_s32 (0));
|
||||
wide_i = vminq_s32 (wide_i, vdupq_n_s32 (maxY));
|
||||
|
||||
/* i<<4 | TILEX_LOW_BITS(fx) */
|
||||
wide_lo = vshrq_n_s32 (wide_y, 12);
|
||||
wide_i = vsliq_n_s32 (wide_lo, wide_i, 4);
|
||||
|
||||
/* i<<14 */
|
||||
wide_i = vshlq_n_s32 (wide_i, 14);
|
||||
|
||||
/* SkClampMax(((f + one)) >> 16, max) */
|
||||
wide_fy1 = vaddq_s32 (wide_y, vdupq_n_s32(oneY));
|
||||
wide_fy1 = vmaxq_s32 (vshrq_n_s32 (wide_fy1, 16), vdupq_n_s32 (0));
|
||||
wide_fy1 = vminq_s32 (wide_fy1, vdupq_n_s32 (maxY));
|
||||
|
||||
/* final combination */
|
||||
wide_y = vorrq_s32 (wide_i, wide_fy1);
|
||||
|
||||
/* switch them around; have to do it this way to get them
|
||||
* in the proper registers to match our instruction */
|
||||
|
||||
/* wide_x/wide_y are fixed regs, in wrong order; swap 'em */
|
||||
wide_first = wide_y;
|
||||
wide_second = wide_x;
|
||||
|
||||
/* iteration bookkeeping, ahead of the asm() for scheduling */
|
||||
srcXY += 2*4;
|
||||
count -= 4;
|
||||
|
||||
/* store interleaved as y-x-y-x-y-x-y-x (NB != read order) */
|
||||
asm ("vst2.32 {q0-q1},[%2] /* y=%q0 x=%q1 */"
|
||||
:
|
||||
: "w" (wide_first), "w" (wide_second), "r" (xy));
|
||||
|
||||
/* on to the next iteration */
|
||||
/* count, srcXY are handled above */
|
||||
xy += 2*4;
|
||||
}
|
||||
}
|
||||
|
||||
/* was do-while; NEON code invalidates original count>0 assumption */
|
||||
while (--count >= 0) {
|
||||
/* NB: we read x/y, we write y/x */
|
||||
*xy++ = PACK_FILTER_Y_NAME(srcXY[1] - (oneY >> 1), maxY,
|
||||
oneY PREAMBLE_ARG_Y);
|
||||
*xy++ = PACK_FILTER_X_NAME(srcXY[0] - (oneX >> 1), maxX,
|
||||
oneX PREAMBLE_ARG_X);
|
||||
srcXY += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SkBitmapProcState::MatrixProc MAKENAME(_Procs)[] = {
|
||||
SCALE_NOFILTER_NAME,
|
||||
SCALE_FILTER_NAME,
|
||||
AFFINE_NOFILTER_NAME,
|
||||
AFFINE_FILTER_NAME,
|
||||
PERSP_NOFILTER_NAME,
|
||||
PERSP_FILTER_NAME
|
||||
};
|
||||
|
||||
#undef MAKENAME
|
||||
#undef TILEX_PROCF
|
||||
#undef TILEY_PROCF
|
||||
#ifdef CHECK_FOR_DECAL
|
||||
#undef CHECK_FOR_DECAL
|
||||
#endif
|
||||
|
||||
#undef SCALE_NOFILTER_NAME
|
||||
#undef SCALE_FILTER_NAME
|
||||
#undef AFFINE_NOFILTER_NAME
|
||||
#undef AFFINE_FILTER_NAME
|
||||
#undef PERSP_NOFILTER_NAME
|
||||
#undef PERSP_FILTER_NAME
|
||||
|
||||
#undef PREAMBLE
|
||||
#undef PREAMBLE_PARAM_X
|
||||
#undef PREAMBLE_PARAM_Y
|
||||
#undef PREAMBLE_ARG_X
|
||||
#undef PREAMBLE_ARG_Y
|
||||
|
||||
#undef TILEX_LOW_BITS
|
||||
#undef TILEY_LOW_BITS
|
|
@ -0,0 +1,580 @@
|
|||
/* NEON optimized code (C) COPYRIGHT 2009 Motorola */
|
||||
/*
|
||||
* Modifications done in-house at Motorola
|
||||
*
|
||||
* this is a clone of SkBitmapProcState_matrix.h
|
||||
* and has been tuned to work with the NEON unit.
|
||||
*
|
||||
* Still going back and forth between whether this approach
|
||||
* (clone the entire SkBitmapProcState_matrix.h file or
|
||||
* if I should put just the modified routines in here and
|
||||
* then use a construct like #define DONT_DO_THIS_FUNCTION or
|
||||
* something like that...
|
||||
*
|
||||
* This is for the RepeatX_RepeatY part of the world
|
||||
*/
|
||||
|
||||
|
||||
#if !defined(__ARM_HAVE_NEON)
|
||||
#error this file can be used only when the NEON unit is enabled
|
||||
#endif
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
/*
|
||||
* This has been modified on the knowledge that (at the time)
|
||||
* we had the following macro definitions in the parent file
|
||||
*
|
||||
* #define MAKENAME(suffix) RepeatX_RepeatY ## suffix
|
||||
* #define TILEX_PROCF(fx, max) (((fx) & 0xFFFF) * ((max) + 1) >> 16)
|
||||
* #define TILEY_PROCF(fy, max) (((fy) & 0xFFFF) * ((max) + 1) >> 16)
|
||||
* #define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
|
||||
* #define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
|
||||
*/
|
||||
|
||||
/* SkClampMax(val,max) -- bound to 0..max */
|
||||
|
||||
#define SCALE_NOFILTER_NAME MAKENAME(_nofilter_scale)
|
||||
#define SCALE_FILTER_NAME MAKENAME(_filter_scale)
|
||||
#define AFFINE_NOFILTER_NAME MAKENAME(_nofilter_affine)
|
||||
#define AFFINE_FILTER_NAME MAKENAME(_filter_affine)
|
||||
#define PERSP_NOFILTER_NAME MAKENAME(_nofilter_persp)
|
||||
#define PERSP_FILTER_NAME MAKENAME(_filter_persp)
|
||||
|
||||
#define PACK_FILTER_X_NAME MAKENAME(_pack_filter_x)
|
||||
#define PACK_FILTER_Y_NAME MAKENAME(_pack_filter_y)
|
||||
|
||||
#ifndef PREAMBLE
|
||||
#define PREAMBLE(state)
|
||||
#define PREAMBLE_PARAM_X
|
||||
#define PREAMBLE_PARAM_Y
|
||||
#define PREAMBLE_ARG_X
|
||||
#define PREAMBLE_ARG_Y
|
||||
#endif
|
||||
|
||||
static void SCALE_NOFILTER_NAME(const SkBitmapProcState& s,
|
||||
uint32_t xy[], int count, int x, int y) {
|
||||
SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
|
||||
SkMatrix::kScale_Mask)) == 0);
|
||||
|
||||
PREAMBLE(s);
|
||||
// we store y, x, x, x, x, x
|
||||
|
||||
const unsigned maxX = s.fBitmap->width() - 1;
|
||||
SkFixed fx;
|
||||
{
|
||||
SkPoint pt;
|
||||
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, &pt);
|
||||
fx = SkScalarToFixed(pt.fY);
|
||||
const unsigned maxY = s.fBitmap->height() - 1;
|
||||
*xy++ = TILEY_PROCF(fx, maxY);
|
||||
fx = SkScalarToFixed(pt.fX);
|
||||
}
|
||||
|
||||
if (0 == maxX) {
|
||||
// all of the following X values must be 0
|
||||
memset(xy, 0, count * sizeof(uint16_t));
|
||||
return;
|
||||
}
|
||||
|
||||
const SkFixed dx = s.fInvSx;
|
||||
|
||||
#ifdef CHECK_FOR_DECAL
|
||||
// test if we don't need to apply the tile proc
|
||||
if ((unsigned)(fx >> 16) <= maxX &&
|
||||
(unsigned)((fx + dx * (count - 1)) >> 16) <= maxX) {
|
||||
decal_nofilter_scale(xy, fx, dx, count);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
int i;
|
||||
|
||||
#if defined(__ARM_HAVE_NEON)
|
||||
/* RBE: very much like done in decal_nofilter ,
|
||||
* but some processing of the 'fx' information
|
||||
* TILEX_PROCF(fx, max) (((fx) & 0xFFFF) * ((max) + 1) >> 16)
|
||||
*/
|
||||
if (count >= 8)
|
||||
{
|
||||
/* SkFixed is 16.16 fixed point */
|
||||
SkFixed dx2 = dx+dx;
|
||||
SkFixed dx4 = dx2+dx2;
|
||||
SkFixed dx8 = dx4+dx4;
|
||||
|
||||
/* now build fx/fx+dx/fx+2dx/fx+3dx */
|
||||
SkFixed fx1, fx2, fx3;
|
||||
int32x2_t lower, upper;
|
||||
int32x4_t lbase, hbase;
|
||||
int16_t *dst16 = (int16_t *)xy;
|
||||
|
||||
fx1 = fx+dx;
|
||||
fx2 = fx1+dx;
|
||||
fx3 = fx2+dx;
|
||||
|
||||
#if 1
|
||||
/* avoid the 'lbase unitialized' warning */
|
||||
lbase = vdupq_n_s32(fx);
|
||||
#else
|
||||
lbase = vsetq_lane_s32(fx, lbase, 0);
|
||||
#endif
|
||||
lbase = vsetq_lane_s32(fx1, lbase, 1);
|
||||
lbase = vsetq_lane_s32(fx2, lbase, 2);
|
||||
lbase = vsetq_lane_s32(fx3, lbase, 3);
|
||||
hbase = vaddq_s32(lbase, vdupq_n_s32(dx4));
|
||||
|
||||
/* store & bump */
|
||||
do
|
||||
{
|
||||
int32x4_t lout;
|
||||
int32x4_t hout;
|
||||
int16x8_t hi16;
|
||||
|
||||
/* TILEX_PROCF(fx, max) (((fx)&0xFFFF)*((max)+1)>> 16) */
|
||||
/* mask to low 16 [would like to use uzp tricks) */
|
||||
lout = vandq_s32(lbase, vdupq_n_s32(0xffff));
|
||||
hout = vandq_s32(hbase, vdupq_n_s32(0xffff));
|
||||
/* bare multiplication, not SkFixedMul */
|
||||
lout = vmulq_s32(lout, vdupq_n_s32(maxX+1));
|
||||
hout = vmulq_s32(hout, vdupq_n_s32(maxX+1));
|
||||
|
||||
/* extraction, using uzp */
|
||||
/* this is ok -- we want all hi(lout)s then all hi(hout)s */
|
||||
asm ("vuzpq.16 %q0, %q1" : "+w" (lout), "+w" (hout));
|
||||
hi16 = vreinterpretq_s16_s32(hout);
|
||||
vst1q_s16(dst16, hi16);
|
||||
|
||||
/* bump our base on to the next */
|
||||
lbase = vaddq_s32 (lbase, vdupq_n_s32(dx8));
|
||||
hbase = vaddq_s32 (hbase, vdupq_n_s32(dx8));
|
||||
dst16 += 8;
|
||||
count -= 8;
|
||||
fx += dx8;
|
||||
} while (count >= 8);
|
||||
xy = (uint32_t *) dst16;
|
||||
}
|
||||
#else
|
||||
/* simple, portable way of looking at 4 at a crack;
|
||||
* so gets some loop unrolling, but not full SIMD speed
|
||||
*/
|
||||
for (i = (count >> 2); i > 0; --i) {
|
||||
unsigned a, b;
|
||||
a = TILEX_PROCF(fx, maxX); fx += dx;
|
||||
b = TILEX_PROCF(fx, maxX); fx += dx;
|
||||
#ifdef SK_CPU_BENDIAN
|
||||
*xy++ = (a << 16) | b;
|
||||
#else
|
||||
*xy++ = (b << 16) | a;
|
||||
#endif
|
||||
a = TILEX_PROCF(fx, maxX); fx += dx;
|
||||
b = TILEX_PROCF(fx, maxX); fx += dx;
|
||||
#ifdef SK_CPU_BENDIAN
|
||||
*xy++ = (a << 16) | b;
|
||||
#else
|
||||
*xy++ = (b << 16) | a;
|
||||
#endif
|
||||
}
|
||||
/* loop doesn't adjust count */
|
||||
count -= (count>>2);
|
||||
#endif
|
||||
uint16_t* xx = (uint16_t*)xy;
|
||||
for (i = count; i > 0; --i) {
|
||||
*xx++ = TILEX_PROCF(fx, maxX); fx += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// note: we could special-case on a matrix which is skewed in X but not Y.
|
||||
// this would require a more general setup thatn SCALE does, but could use
|
||||
// SCALE's inner loop that only looks at dx
|
||||
|
||||
|
||||
static void AFFINE_NOFILTER_NAME(const SkBitmapProcState& s,
|
||||
uint32_t xy[], int count, int x, int y) {
|
||||
SkASSERT(s.fInvType & SkMatrix::kAffine_Mask);
|
||||
SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
|
||||
SkMatrix::kScale_Mask |
|
||||
SkMatrix::kAffine_Mask)) == 0);
|
||||
|
||||
PREAMBLE(s);
|
||||
SkPoint srcPt;
|
||||
s.fInvProc(*s.fInvMatrix,
|
||||
SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
|
||||
|
||||
SkFixed fx = SkScalarToFixed(srcPt.fX);
|
||||
SkFixed fy = SkScalarToFixed(srcPt.fY);
|
||||
SkFixed dx = s.fInvSx;
|
||||
SkFixed dy = s.fInvKy;
|
||||
int maxX = s.fBitmap->width() - 1;
|
||||
int maxY = s.fBitmap->height() - 1;
|
||||
|
||||
#if 1
|
||||
int ocount = count;
|
||||
uint32_t *oxy = xy;
|
||||
SkFixed bfx = fx, bfy=fy, bdx=dx, bdy=dy;
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_HAVE_NEON)
|
||||
|
||||
if (0) { extern void rbe(void); rbe(); }
|
||||
|
||||
/* RBE: benchmarks show this eats up time; can we neonize it? */
|
||||
/* RBE: very much like done in decal_nofilter ,
|
||||
* but some processing of the 'fx' information
|
||||
* TILEX_PROCF(fx, max) (((fx) & 0xFFFF) * ((max) + 1) >> 16)
|
||||
*/
|
||||
if (count >= 4)
|
||||
{
|
||||
/* SkFixed is 16.16 fixed point */
|
||||
SkFixed dx4 = dx*4;
|
||||
SkFixed dy4 = dy*4;
|
||||
|
||||
/* now build fx/fx+dx/fx+2dx/fx+3dx */
|
||||
int32x2_t lower, upper;
|
||||
int32x4_t xbase, ybase;
|
||||
int16_t *dst16 = (int16_t *)xy;
|
||||
|
||||
/* synthesize 4x for both X and Y */
|
||||
#if 1
|
||||
/* avoid the xbase unitialized warning */
|
||||
xbase = vdupq_n_s32(fx);
|
||||
#else
|
||||
xbase = vsetq_lane_s32(fx, xbase, 0);
|
||||
#endif
|
||||
xbase = vsetq_lane_s32(fx+dx, xbase, 1);
|
||||
xbase = vsetq_lane_s32(fx+dx+dx, xbase, 2);
|
||||
xbase = vsetq_lane_s32(fx+dx+dx+dx, xbase, 3);
|
||||
|
||||
#if 1
|
||||
/* avoid the xbase unitialized warning */
|
||||
ybase = vdupq_n_s32(fy);
|
||||
#else
|
||||
ybase = vsetq_lane_s32(fy, ybase, 0);
|
||||
#endif
|
||||
ybase = vsetq_lane_s32(fy+dy, ybase, 1);
|
||||
ybase = vsetq_lane_s32(fy+dy+dy, ybase, 2);
|
||||
ybase = vsetq_lane_s32(fy+dy+dy+dy, ybase, 3);
|
||||
|
||||
/* store & bump */
|
||||
do
|
||||
{
|
||||
int32x4_t xout;
|
||||
int32x4_t yout;
|
||||
int16x8_t hi16;
|
||||
|
||||
/* TILEX_PROCF(fx, max) (((fx)&0xFFFF)*((max)+1)>> 16) */
|
||||
/* mask to low 16 [would like to use uzp tricks) */
|
||||
xout = vandq_s32(xbase, vdupq_n_s32(0xffff));
|
||||
yout = vandq_s32(ybase, vdupq_n_s32(0xffff));
|
||||
/* bare multiplication, not SkFixedMul */
|
||||
xout = vmulq_s32(xout, vdupq_n_s32(maxX+1));
|
||||
yout = vmulq_s32(yout, vdupq_n_s32(maxY+1));
|
||||
|
||||
/* put hi16 from xout over low16 from yout */
|
||||
yout = vsriq_n_s32(yout, xout, 16);
|
||||
|
||||
/* and then yout has the interleaved upper 16's */
|
||||
hi16 = vreinterpretq_s16_s32(yout);
|
||||
vst1q_s16(dst16, hi16);
|
||||
|
||||
/* bump preserved base & on to the next */
|
||||
xbase = vaddq_s32 (xbase, vdupq_n_s32(dx4));
|
||||
ybase = vaddq_s32 (ybase, vdupq_n_s32(dy4));
|
||||
dst16 += 8; /* 8 x16 aka 4x32 */
|
||||
count -= 4;
|
||||
fx += dx4;
|
||||
fy += dy4;
|
||||
} while (count >= 4);
|
||||
xy = (uint32_t *) dst16;
|
||||
}
|
||||
#if 0
|
||||
/* diagnostics... see whether we agree with the NEON code */
|
||||
int bad = 0;
|
||||
uint32_t *myxy = oxy;
|
||||
int myi = (-1);
|
||||
SkFixed ofx = bfx, ofy= bfy, odx= bdx, ody= bdy;
|
||||
for (myi = ocount; myi > 0; --myi) {
|
||||
uint32_t val = (TILEY_PROCF(ofy, maxY) << 16) | TILEX_PROCF(ofx, maxX);
|
||||
if (val != *myxy++) {
|
||||
bad++;
|
||||
break;
|
||||
}
|
||||
ofx += odx; ofy += ody;
|
||||
}
|
||||
if (bad) {
|
||||
SkDebugf("repeat-nofilter-affine fails\n");
|
||||
SkDebugf("count %d myi %d\n", ocount, myi);
|
||||
SkDebugf(" bfx %08x, bdx %08x, bfy %08x bdy %08x\n",
|
||||
bfx, bdx, bfy, bdy);
|
||||
SkDebugf("maxX %08x maxY %08x\n", maxX, maxY);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
for (int i = count; i > 0; --i) {
|
||||
/* fx, fy, dx, dy are all 32 bit 16.16 fixed point */
|
||||
/* (((fx) & 0xFFFF) * ((max) + 1) >> 16) */
|
||||
*xy++ = (TILEY_PROCF(fy, maxY) << 16) | TILEX_PROCF(fx, maxX);
|
||||
fx += dx; fy += dy;
|
||||
}
|
||||
}
|
||||
|
||||
static void PERSP_NOFILTER_NAME(const SkBitmapProcState& s,
|
||||
uint32_t* SK_RESTRICT xy,
|
||||
int count, int x, int y) {
|
||||
SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask);
|
||||
|
||||
PREAMBLE(s);
|
||||
int maxX = s.fBitmap->width() - 1;
|
||||
int maxY = s.fBitmap->height() - 1;
|
||||
|
||||
SkPerspIter iter(*s.fInvMatrix,
|
||||
SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, count);
|
||||
|
||||
while ((count = iter.next()) != 0) {
|
||||
const SkFixed* SK_RESTRICT srcXY = iter.getXY();
|
||||
|
||||
#if defined(__ARM_HAVE_NEON)
|
||||
/* RBE: */
|
||||
/* TILEX_PROCF(fx, max) (((fx) & 0xFFFF) * ((max) + 1) >> 16) */
|
||||
/* it's a little more complicated than what I did for the
|
||||
* clamp case -- where I could immediately snip to the top
|
||||
* 16 bits and do my min/max games there.
|
||||
* ... might only be able to get 4x unrolling here
|
||||
*/
|
||||
|
||||
/* vld2 to get a set of 32x4's ... */
|
||||
/* do the tile[xy]_procf operations */
|
||||
/* which includes doing vuzp to get hi16's */
|
||||
/* store it */
|
||||
/* -- inner loop (other than vld2) can be had from above */
|
||||
|
||||
/* srcXY is a batch of 32 bit numbers X0,Y0,X1,Y1...
|
||||
* but we immediately discard the low 16 bits...
|
||||
* so what we're going to do is vld4, which will give us
|
||||
* xlo,xhi,ylo,yhi distribution and we can ignore the 'lo'
|
||||
* parts....
|
||||
*/
|
||||
if (0) { extern void rbe(void); rbe(); }
|
||||
if (count >= 8) {
|
||||
int32_t *mysrc = (int32_t *) srcXY;
|
||||
int16_t *mydst = (int16_t *) xy;
|
||||
do {
|
||||
register int32x4_t x asm("q0");
|
||||
register int32x4_t y asm("q1");
|
||||
register int32x4_t x2 asm("q2");
|
||||
register int32x4_t y2 asm("q3");
|
||||
|
||||
int16x8_t hi;
|
||||
int16x8_t hi2;
|
||||
|
||||
/* read array of x,y,x,y,x,y */
|
||||
/* vld2 does the de-interleaving for us */
|
||||
/* dependent on register assignments above */
|
||||
asm ("vld2.32 {q0-q1},[%2] /* x=%q0 y=%q1 */"
|
||||
: "=w" (x), "=w" (y)
|
||||
: "r" (mysrc)
|
||||
);
|
||||
|
||||
/* offset == 256 bits == 32 bytes == 8 longs */
|
||||
asm ("vld2.32 {q2-q3},[%2,#32] /* x=%q0 y=%q1 */"
|
||||
: "=w" (x2), "=w" (y2)
|
||||
: "r" (mysrc)
|
||||
);
|
||||
|
||||
/* TILEX_PROCF(fx, max) (((fx)&0xFFFF)*((max)+1)>> 16) */
|
||||
/* mask to low 16 [would like to use uzp tricks) */
|
||||
/* bare multiplication, not SkFixedMul */
|
||||
x = vandq_s32(x, vdupq_n_s32(0xffff));
|
||||
x = vmulq_s32(x, vdupq_n_s32(maxX+1));
|
||||
y = vandq_s32(y, vdupq_n_s32(0xffff));
|
||||
y = vmulq_s32(y, vdupq_n_s32(maxY+1));
|
||||
|
||||
x2 = vandq_s32(x2, vdupq_n_s32(0xffff));
|
||||
x2 = vmulq_s32(x2, vdupq_n_s32(maxX+1));
|
||||
y2 = vandq_s32(y2, vdupq_n_s32(0xffff));
|
||||
y2 = vmulq_s32(y2, vdupq_n_s32(maxY+1));
|
||||
|
||||
/* now collect interleaved high 16's */
|
||||
/* (hi-x, hi-y)4 (hi-x2; hi-y2)4 */
|
||||
|
||||
/* extraction, using uzp, leaves hi16's in y */
|
||||
y = vsriq_n_s32(y, x, 16);
|
||||
hi = vreinterpretq_s16_s32(y);
|
||||
vst1q_s16(mydst, hi);
|
||||
|
||||
/* and get second 8 bytes out */
|
||||
y2 = vsriq_n_s32(y2, x2, 16);
|
||||
hi2 = vreinterpretq_s16_s32(y2);
|
||||
vst1q_s16(mydst+8, hi2);
|
||||
|
||||
/* XXX: gcc isn't interleaving these with the NEON ops
|
||||
* but i think that all the scoreboarding works out */
|
||||
count -= 8; /* 8 iterations */
|
||||
mysrc += 16; /* 16 longs */
|
||||
mydst += 16; /* 16 shorts, aka 8 longs */
|
||||
} while (count >= 8);
|
||||
/* get xy and srcXY fixed up */
|
||||
srcXY = (const SkFixed *) mysrc;
|
||||
xy = (uint32_t *) mydst;
|
||||
}
|
||||
#endif
|
||||
while (--count >= 0) {
|
||||
*xy++ = (TILEY_PROCF(srcXY[1], maxY) << 16) |
|
||||
TILEX_PROCF(srcXY[0], maxX);
|
||||
srcXY += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline uint32_t PACK_FILTER_Y_NAME(SkFixed f, unsigned max,
|
||||
SkFixed one PREAMBLE_PARAM_Y) {
|
||||
unsigned i = TILEY_PROCF(f, max);
|
||||
i = (i << 4) | TILEY_LOW_BITS(f, max);
|
||||
return (i << 14) | (TILEY_PROCF((f + one), max));
|
||||
}
|
||||
|
||||
static inline uint32_t PACK_FILTER_X_NAME(SkFixed f, unsigned max,
|
||||
SkFixed one PREAMBLE_PARAM_X) {
|
||||
unsigned i = TILEX_PROCF(f, max);
|
||||
i = (i << 4) | TILEX_LOW_BITS(f, max);
|
||||
return (i << 14) | (TILEX_PROCF((f + one), max));
|
||||
}
|
||||
|
||||
static void SCALE_FILTER_NAME(const SkBitmapProcState& s,
|
||||
uint32_t xy[], int count, int x, int y) {
|
||||
SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
|
||||
SkMatrix::kScale_Mask)) == 0);
|
||||
SkASSERT(s.fInvKy == 0);
|
||||
|
||||
PREAMBLE(s);
|
||||
|
||||
const unsigned maxX = s.fBitmap->width() - 1;
|
||||
const SkFixed one = s.fFilterOneX;
|
||||
const SkFixed dx = s.fInvSx;
|
||||
SkFixed fx;
|
||||
|
||||
{
|
||||
SkPoint pt;
|
||||
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, &pt);
|
||||
const SkFixed fy = SkScalarToFixed(pt.fY) - (s.fFilterOneY >> 1);
|
||||
const unsigned maxY = s.fBitmap->height() - 1;
|
||||
// compute our two Y values up front
|
||||
*xy++ = PACK_FILTER_Y_NAME(fy, maxY, s.fFilterOneY PREAMBLE_ARG_Y);
|
||||
// now initialize fx
|
||||
fx = SkScalarToFixed(pt.fX) - (one >> 1);
|
||||
}
|
||||
|
||||
#ifdef CHECK_FOR_DECAL
|
||||
// test if we don't need to apply the tile proc
|
||||
if (dx > 0 &&
|
||||
(unsigned)(fx >> 16) <= maxX &&
|
||||
(unsigned)((fx + dx * (count - 1)) >> 16) < maxX) {
|
||||
decal_filter_scale(xy, fx, dx, count);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
do {
|
||||
*xy++ = PACK_FILTER_X_NAME(fx, maxX, one PREAMBLE_ARG_X);
|
||||
fx += dx;
|
||||
} while (--count != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void AFFINE_FILTER_NAME(const SkBitmapProcState& s,
|
||||
uint32_t xy[], int count, int x, int y) {
|
||||
SkASSERT(s.fInvType & SkMatrix::kAffine_Mask);
|
||||
SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
|
||||
SkMatrix::kScale_Mask |
|
||||
SkMatrix::kAffine_Mask)) == 0);
|
||||
|
||||
PREAMBLE(s);
|
||||
SkPoint srcPt;
|
||||
s.fInvProc(*s.fInvMatrix,
|
||||
SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
|
||||
|
||||
SkFixed oneX = s.fFilterOneX;
|
||||
SkFixed oneY = s.fFilterOneY;
|
||||
SkFixed fx = SkScalarToFixed(srcPt.fX) - (oneX >> 1);
|
||||
SkFixed fy = SkScalarToFixed(srcPt.fY) - (oneY >> 1);
|
||||
SkFixed dx = s.fInvSx;
|
||||
SkFixed dy = s.fInvKy;
|
||||
unsigned maxX = s.fBitmap->width() - 1;
|
||||
unsigned maxY = s.fBitmap->height() - 1;
|
||||
|
||||
do {
|
||||
*xy++ = PACK_FILTER_Y_NAME(fy, maxY, oneY PREAMBLE_ARG_Y);
|
||||
fy += dy;
|
||||
*xy++ = PACK_FILTER_X_NAME(fx, maxX, oneX PREAMBLE_ARG_X);
|
||||
fx += dx;
|
||||
} while (--count != 0);
|
||||
}
|
||||
|
||||
static void PERSP_FILTER_NAME(const SkBitmapProcState& s,
|
||||
uint32_t* SK_RESTRICT xy, int count,
|
||||
int x, int y) {
|
||||
SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask);
|
||||
|
||||
extern void rbe(void);
|
||||
|
||||
PREAMBLE(s);
|
||||
unsigned maxX = s.fBitmap->width() - 1;
|
||||
unsigned maxY = s.fBitmap->height() - 1;
|
||||
SkFixed oneX = s.fFilterOneX;
|
||||
SkFixed oneY = s.fFilterOneY;
|
||||
|
||||
|
||||
|
||||
SkPerspIter iter(*s.fInvMatrix,
|
||||
SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, count);
|
||||
|
||||
while ((count = iter.next()) != 0) {
|
||||
const SkFixed* SK_RESTRICT srcXY = iter.getXY();
|
||||
do {
|
||||
*xy++ = PACK_FILTER_Y_NAME(srcXY[1] - (oneY >> 1), maxY,
|
||||
oneY PREAMBLE_ARG_Y);
|
||||
*xy++ = PACK_FILTER_X_NAME(srcXY[0] - (oneX >> 1), maxX,
|
||||
oneX PREAMBLE_ARG_X);
|
||||
srcXY += 2;
|
||||
} while (--count != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static SkBitmapProcState::MatrixProc MAKENAME(_Procs)[] = {
|
||||
SCALE_NOFILTER_NAME,
|
||||
SCALE_FILTER_NAME,
|
||||
AFFINE_NOFILTER_NAME,
|
||||
AFFINE_FILTER_NAME,
|
||||
PERSP_NOFILTER_NAME,
|
||||
PERSP_FILTER_NAME
|
||||
};
|
||||
|
||||
#undef MAKENAME
|
||||
#undef TILEX_PROCF
|
||||
#undef TILEY_PROCF
|
||||
#ifdef CHECK_FOR_DECAL
|
||||
#undef CHECK_FOR_DECAL
|
||||
#endif
|
||||
|
||||
#undef SCALE_NOFILTER_NAME
|
||||
#undef SCALE_FILTER_NAME
|
||||
#undef AFFINE_NOFILTER_NAME
|
||||
#undef AFFINE_FILTER_NAME
|
||||
#undef PERSP_NOFILTER_NAME
|
||||
#undef PERSP_FILTER_NAME
|
||||
|
||||
#undef PREAMBLE
|
||||
#undef PREAMBLE_PARAM_X
|
||||
#undef PREAMBLE_PARAM_Y
|
||||
#undef PREAMBLE_ARG_X
|
||||
#undef PREAMBLE_ARG_Y
|
||||
|
||||
#undef TILEX_LOW_BITS
|
||||
#undef TILEY_LOW_BITS
|
|
@ -23,6 +23,7 @@
|
|||
00003C9E0EFC233F000FF73A /* SkDOM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00003C9A0EFC233F000FF73A /* SkDOM.cpp */; };
|
||||
00003CA10EFC233F000FF73A /* SkXMLParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00003C9D0EFC233F000FF73A /* SkXMLParser.cpp */; };
|
||||
00003CA40EFC235F000FF73A /* SkXMLParser_empty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00003CA30EFC235F000FF73A /* SkXMLParser_empty.cpp */; };
|
||||
0009E2201057E96800B0DE6F /* SampleStrokePath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0009E21F1057E96800B0DE6F /* SampleStrokePath.cpp */; };
|
||||
000A99820FD97526007E45BD /* SampleArc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00A41E4A0EFC312F00C9CBEB /* SampleArc.cpp */; };
|
||||
001B871E1042184D00C84ED4 /* Forth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 001B871D1042184D00C84ED4 /* Forth.cpp */; };
|
||||
0028847B0EFAB46A0083E387 /* libcore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 002884510EFAA35C0083E387 /* libcore.a */; };
|
||||
|
@ -75,6 +76,7 @@
|
|||
00AF9B18103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00AF9B17103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp */; };
|
||||
00BB289B104781D00057BF7E /* SampleForth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00BB289A104781D00057BF7E /* SampleForth.cpp */; };
|
||||
00C1B809103857A400FA5948 /* SampleFillType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE270F00A12400695E8C /* SampleFillType.cpp */; };
|
||||
00EB4593104DBB18002B413E /* ForthTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00EB4592104DBB18002B413E /* ForthTests.cpp */; };
|
||||
00ED55F3104A10EB00F51FF8 /* StdWords.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00ED55F2104A10EB00F51FF8 /* StdWords.cpp */; };
|
||||
00F53F480FFCFC4D003FA70A /* SampleGradients.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00C55DA00F8552DC000CAC09 /* SampleGradients.cpp */; };
|
||||
00FF39140FC6ED2C00915187 /* SampleEffects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00FF39130FC6ED2C00915187 /* SampleEffects.cpp */; };
|
||||
|
@ -153,6 +155,7 @@
|
|||
00003C9A0EFC233F000FF73A /* SkDOM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkDOM.cpp; path = ../../src/xml/SkDOM.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00003C9D0EFC233F000FF73A /* SkXMLParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkXMLParser.cpp; path = ../../src/xml/SkXMLParser.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00003CA30EFC235F000FF73A /* SkXMLParser_empty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkXMLParser_empty.cpp; path = ../../src/ports/SkXMLParser_empty.cpp; sourceTree = SOURCE_ROOT; };
|
||||
0009E21F1057E96800B0DE6F /* SampleStrokePath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleStrokePath.cpp; path = ../../samplecode/SampleStrokePath.cpp; sourceTree = SOURCE_ROOT; };
|
||||
001B871D1042184D00C84ED4 /* Forth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Forth.cpp; path = ../../forth/Forth.cpp; sourceTree = SOURCE_ROOT; };
|
||||
002884490EFAA35C0083E387 /* core.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = core.xcodeproj; path = ../core/core.xcodeproj; sourceTree = SOURCE_ROOT; };
|
||||
002884B40EFAB69F0083E387 /* maccore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = maccore.xcodeproj; path = ../maccore/maccore.xcodeproj; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -208,6 +211,7 @@
|
|||
00BB289A104781D00057BF7E /* SampleForth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleForth.cpp; path = ../../forth/SampleForth.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00C55DA00F8552DC000CAC09 /* SampleGradients.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleGradients.cpp; path = ../../samplecode/SampleGradients.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00D6B5CB0F72DC4300C466B9 /* SampleFuzz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFuzz.cpp; path = ../../samplecode/SampleFuzz.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00EB4592104DBB18002B413E /* ForthTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ForthTests.cpp; path = ../../forth/ForthTests.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00ED55F2104A10EB00F51FF8 /* StdWords.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StdWords.cpp; path = ../../forth/StdWords.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00FF39130FC6ED2C00915187 /* SampleEffects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleEffects.cpp; path = ../../samplecode/SampleEffects.cpp; sourceTree = SOURCE_ROOT; };
|
||||
0156F80307C56A3000C6122B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
||||
|
@ -289,6 +293,7 @@
|
|||
0041CE270F00A12400695E8C /* SampleFillType.cpp */,
|
||||
00AF9B17103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp */,
|
||||
00840B74104C69F5005B3EDC /* SampleExtractAlpha.cpp */,
|
||||
0009E21F1057E96800B0DE6F /* SampleStrokePath.cpp */,
|
||||
0041CE280F00A12400695E8C /* SampleFilter.cpp */,
|
||||
0041CE290F00A12400695E8C /* SampleFilter2.cpp */,
|
||||
0041CE2A0F00A12400695E8C /* SampleFontCache.cpp */,
|
||||
|
@ -366,6 +371,7 @@
|
|||
children = (
|
||||
001B871D1042184D00C84ED4 /* Forth.cpp */,
|
||||
00ED55F2104A10EB00F51FF8 /* StdWords.cpp */,
|
||||
00EB4592104DBB18002B413E /* ForthTests.cpp */,
|
||||
00BB289A104781D00057BF7E /* SampleForth.cpp */,
|
||||
2762F66A0FCCCAA2002BD8B4 /* images */,
|
||||
00003C6A0EFC22AD000FF73A /* views */,
|
||||
|
@ -595,6 +601,8 @@
|
|||
00BB289B104781D00057BF7E /* SampleForth.cpp in Sources */,
|
||||
00ED55F3104A10EB00F51FF8 /* StdWords.cpp in Sources */,
|
||||
00840B75104C69F5005B3EDC /* SampleExtractAlpha.cpp in Sources */,
|
||||
00EB4593104DBB18002B413E /* ForthTests.cpp in Sources */,
|
||||
0009E2201057E96800B0DE6F /* SampleStrokePath.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче