New bitmap filter checkin; this time with less build breakage

BUG=

Review URL: https://codereview.chromium.org/18942002

git-svn-id: http://skia.googlecode.com/svn/trunk@9944 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
humper@google.com 2013-07-09 21:37:14 +00:00
Родитель 6e8b7ddefd
Коммит b088947f27
18 изменённых файлов: 1048 добавлений и 219 удалений

Просмотреть файл

@ -149,7 +149,7 @@ protected:
int count = N; int count = N;
#ifdef SK_RELEASE #ifdef SK_RELEASE
// in DEBUG, N is always 1 // in DEBUG, N is always 1
if (paint.getFlags() & SkPaint::kBicubicFilterBitmap_Flag) { if (paint.getFlags() & SkPaint::kHighQualityFilterBitmap_Flag) {
count /= BICUBIC_DUR_SCALE; count /= BICUBIC_DUR_SCALE;
} }
#endif #endif
@ -170,7 +170,7 @@ protected:
#ifdef SK_DEBUG #ifdef SK_DEBUG
return 1; return 1;
#else #else
return (paint.getFlags() & SkPaint::kBicubicFilterBitmap_Flag) ? return (paint.getFlags() & SkPaint::kHighQualityFilterBitmap_Flag) ?
(float)BICUBIC_DUR_SCALE : 1; (float)BICUBIC_DUR_SCALE : 1;
#endif #endif
} }
@ -266,12 +266,12 @@ protected:
} }
uint32_t orMask = 0; uint32_t orMask = 0;
uint32_t clearMask = SkPaint::kFilterBitmap_Flag | SkPaint::kBicubicFilterBitmap_Flag; uint32_t clearMask = SkPaint::kFilterBitmap_Flag | SkPaint::kHighQualityFilterBitmap_Flag;
if (fFlags & kBilerp_Flag) { if (fFlags & kBilerp_Flag) {
orMask |= SkPaint::kFilterBitmap_Flag; orMask |= SkPaint::kFilterBitmap_Flag;
} }
if (fFlags & kBicubic_Flag) { if (fFlags & kBicubic_Flag) {
orMask |= SkPaint::kBicubicFilterBitmap_Flag; orMask |= SkPaint::kHighQualityFilterBitmap_Flag;
} }
this->setPaintMasks(orMask, clearMask); this->setPaintMasks(orMask, clearMask);

135
bench/BitmapScaleBench.cpp Normal file
Просмотреть файл

@ -0,0 +1,135 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkBenchmark.h"
#include "SkCanvas.h"
#include "SkPaint.h"
#include "SkRandom.h"
#include "SkShader.h"
#include "SkString.h"
#include "SkBlurMask.h"
class BitmapScaleBench: public SkBenchmark {
int fLoopCount;
int fInputSize;
int fOutputSize;
SkString fName;
public:
BitmapScaleBench(void *param, int is, int os) : INHERITED(param) {
fInputSize = is;
fOutputSize = os;
fLoopCount = 100;
}
protected:
SkBitmap fInputBitmap, fOutputBitmap;
SkMatrix fMatrix;
virtual const char* onGetName() {
return fName.c_str();
}
int inputSize() const {
return fInputSize;
}
int outputSize() const {
return fOutputSize;
}
float scale() const {
return float(outputSize())/inputSize();
}
SkIPoint onGetSize() SK_OVERRIDE {
return SkIPoint::Make( fOutputSize, fOutputSize );
}
void setName(const char * name) {
fName.printf( "bitmap_scale_%s_%d_%d", name, fInputSize, fOutputSize );
}
virtual void onPreDraw() {
fInputBitmap.setConfig(SkBitmap::kARGB_8888_Config, fInputSize, fInputSize);
fInputBitmap.allocPixels();
fInputBitmap.eraseColor(SK_ColorWHITE);
fInputBitmap.setIsOpaque(true);
fOutputBitmap.setConfig(SkBitmap::kARGB_8888_Config, fOutputSize, fOutputSize);
fOutputBitmap.allocPixels();
fOutputBitmap.setIsOpaque(true);
fMatrix.setScale( scale(), scale() );
}
virtual void onDraw(SkCanvas*) {
SkPaint paint;
this->setupPaint(&paint);
preBenchSetup();
for (int i = 0; i < SkBENCHLOOP(fLoopCount); i++) {
doScaleImage();
}
}
virtual void doScaleImage() = 0;
virtual void preBenchSetup() {}
private:
typedef SkBenchmark INHERITED;
};
class BitmapFilterScaleBench: public BitmapScaleBench {
public:
BitmapFilterScaleBench(void *param, int is, int os) : INHERITED(param, is, os) {
setName( "filter" );
}
protected:
virtual void doScaleImage() SK_OVERRIDE {
SkCanvas canvas( fOutputBitmap );
SkPaint paint;
paint.setFlags( SkPaint::kHighQualityFilterBitmap_Flag | SkPaint::kFilterBitmap_Flag );
canvas.drawBitmapMatrix( fInputBitmap, fMatrix, &paint );
}
private:
typedef BitmapScaleBench INHERITED;
};
class BitmapDirectScaleBench: public BitmapScaleBench {
public:
BitmapDirectScaleBench(void *param, int is, int os) : INHERITED(param, is, os) {
setName( "direct" );
}
protected:
virtual void doScaleImage() SK_OVERRIDE {
fInputBitmap.scale( &fOutputBitmap );
}
private:
typedef BitmapScaleBench INHERITED;
};
DEF_BENCH(return new BitmapFilterScaleBench(p, 10, 90);)
DEF_BENCH(return new BitmapFilterScaleBench(p, 30, 90);)
DEF_BENCH(return new BitmapFilterScaleBench(p, 80, 90);)
// DEF_BENCH(return new BitmapFilterScaleBench(p, 90, 90);)
// DEF_BENCH(return new BitmapFilterScaleBench(p, 90, 80);)
// DEF_BENCH(return new BitmapFilterScaleBench(p, 90, 30);)
// DEF_BENCH(return new BitmapFilterScaleBench(p, 90, 10);)
DEF_BENCH(return new BitmapDirectScaleBench(p, 10, 90);)
DEF_BENCH(return new BitmapDirectScaleBench(p, 30, 90);)
DEF_BENCH(return new BitmapDirectScaleBench(p, 80, 90);)
// DEF_BENCH(return new BitmapDirectScaleBench(p, 90, 90);)
// DEF_BENCH(return new BitmapDirectScaleBench(p, 90, 80);)
// DEF_BENCH(return new BitmapDirectScaleBench(p, 90, 30);)
// DEF_BENCH(return new BitmapDirectScaleBench(p, 90, 10);)

Просмотреть файл

@ -35,7 +35,7 @@ static void draw_col(SkCanvas* canvas, const SkBitmap& bm, const SkMatrix& mat,
canvas->translate(dx, 0); canvas->translate(dx, 0);
canvas->drawBitmapMatrix(bm, mat, &paint); canvas->drawBitmapMatrix(bm, mat, &paint);
paint.setFlags(paint.getFlags() | SkPaint::kBicubicFilterBitmap_Flag); paint.setFlags(paint.getFlags() | SkPaint::kHighQualityFilterBitmap_Flag);
canvas->translate(dx, 0); canvas->translate(dx, 0);
canvas->drawBitmapMatrix(bm, mat, &paint); canvas->drawBitmapMatrix(bm, mat, &paint);
} }
@ -64,7 +64,7 @@ public:
this->setBGColor(0xFFDDDDDD); this->setBGColor(0xFFDDDDDD);
} }
void setName( const char name[] ) { void setName(const char name[]) {
fName.set(name); fName.set(name);
} }
@ -99,12 +99,12 @@ private:
class FilterBitmapTextGM: public FilterBitmapGM { class FilterBitmapTextGM: public FilterBitmapGM {
public: public:
FilterBitmapTextGM( float textSize ) FilterBitmapTextGM(float textSize)
: fTextSize( textSize ) : fTextSize(textSize)
{ {
char name[1024]; char name[1024];
sprintf( name, "filterbitmap_text_%.2fpt", fTextSize ); sprintf(name, "filterbitmap_text_%.2fpt", fTextSize);
setName( name ); setName(name);
} }
protected: protected:
@ -140,12 +140,12 @@ class FilterBitmapTextGM: public FilterBitmapGM {
class FilterBitmapCheckerboardGM: public FilterBitmapGM { class FilterBitmapCheckerboardGM: public FilterBitmapGM {
public: public:
FilterBitmapCheckerboardGM( int size, int num_checks ) FilterBitmapCheckerboardGM(int size, int num_checks)
: fSize( size ), fNumChecks( num_checks ) : fSize(size), fNumChecks(num_checks)
{ {
char name[1024]; char name[1024];
sprintf( name, "filterbitmap_checkerboard_%d_%d", fSize, fNumChecks ); sprintf(name, "filterbitmap_checkerboard_%d_%d", fSize, fNumChecks);
setName( name ); setName(name);
} }
protected: protected:
@ -179,12 +179,12 @@ class FilterBitmapCheckerboardGM: public FilterBitmapGM {
class FilterBitmapImageGM: public FilterBitmapGM { class FilterBitmapImageGM: public FilterBitmapGM {
public: public:
FilterBitmapImageGM( const char filename[] ) FilterBitmapImageGM(const char filename[])
: fFilename( filename ) : fFilename(filename)
{ {
char name[1024]; char name[1024];
sprintf( name, "filterbitmap_image_%s", filename ); sprintf(name, "filterbitmap_image_%s", filename);
setName( name ); setName(name);
} }
protected: protected:
@ -197,7 +197,7 @@ class FilterBitmapImageGM: public FilterBitmapGM {
void make_bitmap() SK_OVERRIDE { void make_bitmap() SK_OVERRIDE {
SkString path(skiagm::GM::gResourcePath); SkString path(skiagm::GM::gResourcePath);
path.append( "/" ); path.append("/");
path.append(fFilename); path.append(fFilename);
SkImageDecoder *codec = NULL; SkImageDecoder *codec = NULL;

114
gm/scalebitmap.cpp Normal file
Просмотреть файл

@ -0,0 +1,114 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm.h"
#include "SkImageDecoder.h"
#include "SkStream.h"
class ScaleBitmapGM : public skiagm::GM {
public:
ScaleBitmapGM(const char filename[], float scale)
: fFilename(filename), fScale(scale)
{
this->setBGColor(0xFFDDDDDD);
fName.printf("scalebitmap_%s_%f", filename, scale);
SkString path(skiagm::GM::gResourcePath);
path.append("/");
path.append(fFilename);
SkImageDecoder *codec = NULL;
SkFILEStream stream(path.c_str());
if (stream.isValid()) {
codec = SkImageDecoder::Factory(&stream);
}
if (codec) {
stream.rewind();
codec->decode(&stream, &fBM, SkBitmap::kARGB_8888_Config,
SkImageDecoder::kDecodePixels_Mode);
SkDELETE(codec);
} else {
fBM.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
fBM.allocPixels();
*(fBM.getAddr32(0,0)) = 0xFF0000FF; // red == bad
}
fSize = fBM.height();
}
protected:
SkBitmap fBM;
SkString fName;
SkString fFilename;
int fSize;
float fScale;
virtual SkString onShortName() SK_OVERRIDE {
return fName;
}
virtual SkISize onISize() SK_OVERRIDE {
return SkISize::Make(fBM.width() * fScale, fBM.height() * fScale);
}
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
SkBitmap dst;
dst.setConfig(SkBitmap::kARGB_8888_Config, fBM.width() * fScale, fBM.height() * fScale);
dst.allocPixels();
fBM.scale(&dst);
canvas->drawBitmap(dst, 0, 0);
}
private:
typedef skiagm::GM INHERITED;
};
class ScaleBitmapMipmapGM: public ScaleBitmapGM {
SkMatrix fMatrix;
public:
ScaleBitmapMipmapGM(const char filename[], float scale)
: INHERITED(filename, scale)
{
fName.printf("scalebitmap_mipmap_%s_%f", filename, scale);
fBM.buildMipMap();
fMatrix.setScale(scale, scale);
}
protected:
virtual void onDraw(SkCanvas *canvas) SK_OVERRIDE {
SkPaint paint;
paint.setFilterBitmap(true);
canvas->drawBitmapMatrix(fBM, fMatrix, &paint);
}
private:
typedef ScaleBitmapGM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_GM( return new ScaleBitmapGM("mandrill_128.png", 2); )
DEF_GM( return new ScaleBitmapGM("mandrill_64.png", 4); )
DEF_GM( return new ScaleBitmapGM("mandrill_32.png", 8); )
DEF_GM( return new ScaleBitmapGM("mandrill_16.png", 16); )
DEF_GM( return new ScaleBitmapGM("nature.jpg", 0.5f); )
DEF_GM( return new ScaleBitmapGM("nature.jpg", 0.25f); )
DEF_GM( return new ScaleBitmapGM("nature.jpg", 0.125f); )
DEF_GM( return new ScaleBitmapGM("nature.jpg", 0.0625f); )
DEF_GM( return new ScaleBitmapMipmapGM("nature.jpg", 0.5f); )
DEF_GM( return new ScaleBitmapMipmapGM("nature.jpg", 0.25f); )
DEF_GM( return new ScaleBitmapMipmapGM("nature.jpg", 0.125f); )
DEF_GM( return new ScaleBitmapMipmapGM("nature.jpg", 0.0625f); )

Просмотреть файл

@ -5,7 +5,6 @@
'../bench/benchmain.cpp', '../bench/benchmain.cpp',
'../bench/SkBenchmark.h', '../bench/SkBenchmark.h',
'../bench/SkBenchmark.cpp', '../bench/SkBenchmark.cpp',
'../bench/AAClipBench.cpp', '../bench/AAClipBench.cpp',
'../bench/BicubicBench.cpp', '../bench/BicubicBench.cpp',
'../bench/BitmapBench.cpp', '../bench/BitmapBench.cpp',

Просмотреть файл

@ -21,13 +21,14 @@
'<(skia_src_path)/core/SkBBoxHierarchyRecord.cpp', '<(skia_src_path)/core/SkBBoxHierarchyRecord.cpp',
'<(skia_src_path)/core/SkBBoxHierarchyRecord.h', '<(skia_src_path)/core/SkBBoxHierarchyRecord.h',
'<(skia_src_path)/core/SkBitmap.cpp', '<(skia_src_path)/core/SkBitmap.cpp',
'<(skia_src_path)/core/SkBitmapFilter.h',
'<(skia_src_path)/core/SkBitmapFilter.cpp',
'<(skia_src_path)/core/SkBitmapHeap.cpp', '<(skia_src_path)/core/SkBitmapHeap.cpp',
'<(skia_src_path)/core/SkBitmapHeap.h', '<(skia_src_path)/core/SkBitmapHeap.h',
'<(skia_src_path)/core/SkBitmapProcShader.cpp', '<(skia_src_path)/core/SkBitmapProcShader.cpp',
'<(skia_src_path)/core/SkBitmapProcShader.h', '<(skia_src_path)/core/SkBitmapProcShader.h',
'<(skia_src_path)/core/SkBitmapProcState.cpp', '<(skia_src_path)/core/SkBitmapProcState.cpp',
'<(skia_src_path)/core/SkBitmapProcState.h', '<(skia_src_path)/core/SkBitmapProcState.h',
'<(skia_src_path)/core/SkBitmapProcBicubic.cpp',
'<(skia_src_path)/core/SkBitmapProcState_matrix.h', '<(skia_src_path)/core/SkBitmapProcState_matrix.h',
'<(skia_src_path)/core/SkBitmapProcState_matrixProcs.cpp', '<(skia_src_path)/core/SkBitmapProcState_matrixProcs.cpp',
'<(skia_src_path)/core/SkBitmapProcState_sample.h', '<(skia_src_path)/core/SkBitmapProcState_sample.h',

Просмотреть файл

@ -90,6 +90,7 @@
'../gm/rrects.cpp', '../gm/rrects.cpp',
'../gm/roundrects.cpp', '../gm/roundrects.cpp',
'../gm/samplerstress.cpp', '../gm/samplerstress.cpp',
# '../gm/scalebitmap.cpp',
'../gm/shaderbounds.cpp', '../gm/shaderbounds.cpp',
'../gm/selftest.cpp', '../gm/selftest.cpp',
'../gm/shadertext.cpp', '../gm/shadertext.cpp',

Просмотреть файл

@ -43,9 +43,13 @@
], ],
}], }],
], ],
'include_dirs': [
'../include/utils',
],
'sources': [ 'sources': [
'../src/opts/opts_check_SSE2.cpp', '../src/opts/opts_check_SSE2.cpp',
'../src/opts/SkBitmapProcState_opts_SSE2.cpp', '../src/opts/SkBitmapProcState_opts_SSE2.cpp',
'../src/opts/SkBitmapFilter_opts_SSE2.cpp',
'../src/opts/SkBlitRow_opts_SSE2.cpp', '../src/opts/SkBlitRow_opts_SSE2.cpp',
'../src/opts/SkBlitRect_opts_SSE2.cpp', '../src/opts/SkBlitRect_opts_SSE2.cpp',
'../src/opts/SkUtils_opts_SSE2.cpp', '../src/opts/SkUtils_opts_SSE2.cpp',

Просмотреть файл

@ -538,7 +538,7 @@ public:
by calling copyTo(). by calling copyTo().
*/ */
bool canCopyTo(Config newConfig) const; bool canCopyTo(Config newConfig) const;
/** /**
* DEPRECATED -- will be replaced with API on SkPaint * DEPRECATED -- will be replaced with API on SkPaint
*/ */
@ -702,6 +702,18 @@ private:
int extractMipLevel(SkBitmap* dst, SkFixed sx, SkFixed sy); int extractMipLevel(SkBitmap* dst, SkFixed sx, SkFixed sy);
bool hasMipMap() const; bool hasMipMap() const;
void freeMipMap(); void freeMipMap();
/** Make a scaled copy of this bitmap into the provided destination.
* The caller is responsible for having set the width and height of the
* provided destination bitmap, and also having allocated its pixel
* memory.
*
* This function is temporary and for testing purposes only; it will
* likely move once it has been properly plumbed into the bitmap
* shader infrastructure.
*/
void scale(SkBitmap *dst) const;
friend struct SkBitmapProcState; friend struct SkBitmapProcState;
}; };

Просмотреть файл

@ -43,11 +43,14 @@ typedef const SkGlyph& (*SkDrawCacheProc)(SkGlyphCache*, const char**,
typedef const SkGlyph& (*SkMeasureCacheProc)(SkGlyphCache*, const char**); typedef const SkGlyph& (*SkMeasureCacheProc)(SkGlyphCache*, const char**);
#define kBicubicFilterBitmap_Flag kHighQualityFilterBitmap_Flag
/** \class SkPaint /** \class SkPaint
The SkPaint class holds the style and color information about how to draw The SkPaint class holds the style and color information about how to draw
geometries, text and bitmaps. geometries, text and bitmaps.
*/ */
class SK_API SkPaint { class SK_API SkPaint {
public: public:
SkPaint(); SkPaint();
@ -108,7 +111,7 @@ public:
kAutoHinting_Flag = 0x800, //!< mask to force Freetype's autohinter kAutoHinting_Flag = 0x800, //!< mask to force Freetype's autohinter
kVerticalText_Flag = 0x1000, kVerticalText_Flag = 0x1000,
kGenA8FromLCD_Flag = 0x2000, // hack for GDI -- do not use if you can help it kGenA8FromLCD_Flag = 0x2000, // hack for GDI -- do not use if you can help it
kBicubicFilterBitmap_Flag = 0x4000, // temporary flag kHighQualityFilterBitmap_Flag = 0x4000, // temporary flag
kHighQualityDownsampleBitmap_Flag = 0x8000, // temporary flag kHighQualityDownsampleBitmap_Flag = 0x8000, // temporary flag
// when adding extra flags, note that the fFlags member is specified // when adding extra flags, note that the fFlags member is specified

374
src/core/SkBitmapFilter.cpp Normal file
Просмотреть файл

@ -0,0 +1,374 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkBitmapProcState.h"
#include "SkBitmap.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkUnPreMultiply.h"
#include "SkShader.h"
#include "SkRTConf.h"
#include "SkMath.h"
void highQualityFilter(const SkBitmapProcState& s, int x, int y,
SkPMColor* SK_RESTRICT colors, int count) {
const int maxX = s.fBitmap->width() - 1;
const int maxY = s.fBitmap->height() - 1;
while (count-- > 0) {
SkPoint srcPt;
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x),
SkIntToScalar(y), &srcPt);
srcPt.fX -= SK_ScalarHalf;
srcPt.fY -= SK_ScalarHalf;
int sx = SkScalarFloorToInt(srcPt.fX);
int sy = SkScalarFloorToInt(srcPt.fY);
SkFixed weight = 0;
SkFixed fr = 0, fg = 0, fb = 0, fa = 0;
int y0 = SkClampMax(int(ceil(sy-s.getBitmapFilter()->width() + 0.5f)), maxY);
int y1 = SkClampMax(int(floor(sy+s.getBitmapFilter()->width() + 0.5f)), maxY);
int x0 = SkClampMax(int(ceil(sx-s.getBitmapFilter()->width() + 0.5f)), maxX);
int x1 = SkClampMax(int(floor(sx+s.getBitmapFilter()->width() + 0.5f)), maxX);
for (int src_y = y0; src_y <= y1; src_y++) {
SkFixed yweight = s.getBitmapFilter()->lookup((srcPt.fY - src_y));
for (int src_x = x0; src_x <= x1 ; src_x++) {
SkFixed xweight = s.getBitmapFilter()->lookup((srcPt.fX - src_x));
SkFixed combined_weight = SkFixedMul(xweight, yweight);
SkPMColor c = *s.fBitmap->getAddr32(src_x, src_y);
fr += combined_weight * SkGetPackedR32(c);
fg += combined_weight * SkGetPackedG32(c);
fb += combined_weight * SkGetPackedB32(c);
fa += combined_weight * SkGetPackedA32(c);
weight += combined_weight;
}
}
fr = SkFixedDiv(fr, weight);
fg = SkFixedDiv(fg, weight);
fb = SkFixedDiv(fb, weight);
fa = SkFixedDiv(fa, weight);
int a = SkClampMax(SkFixedRoundToInt(fa), 255);
int r = SkClampMax(SkFixedRoundToInt(fr), a);
int g = SkClampMax(SkFixedRoundToInt(fg), a);
int b = SkClampMax(SkFixedRoundToInt(fb), a);
*colors++ = SkPackARGB32(a, r, g, b);
x++;
}
}
void highQualityFilter_ScaleOnly(const SkBitmapProcState &s, int x, int y,
SkPMColor *SK_RESTRICT colors, int count) {
const int maxX = s.fBitmap->width() - 1;
const int maxY = s.fBitmap->height() - 1;
SkPoint srcPt;
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x),
SkIntToScalar(y), &srcPt);
srcPt.fY -= SK_ScalarHalf;
int sy = SkScalarFloorToInt(srcPt.fY);
int y0 = SkClampMax(int(ceil(sy-s.getBitmapFilter()->width() + 0.5f)), maxY);
int y1 = SkClampMax(int(floor(sy+s.getBitmapFilter()->width() + 0.5f)), maxY);
while (count-- > 0) {
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x),
SkIntToScalar(y), &srcPt);
srcPt.fX -= SK_ScalarHalf;
srcPt.fY -= SK_ScalarHalf;
int sx = SkScalarFloorToInt(srcPt.fX);
SkFixed weight = 0;
SkFixed fr = 0, fg = 0, fb = 0, fa = 0;
int x0 = SkClampMax(int(ceil(sx-s.getBitmapFilter()->width() + 0.5f)), maxX);
int x1 = SkClampMax(int(floor(sx+s.getBitmapFilter()->width() + 0.5f)), maxX);
for (int src_y = y0; src_y <= y1; src_y++) {
SkFixed yweight = s.getBitmapFilter()->lookup((srcPt.fY - src_y));
for (int src_x = x0; src_x <= x1 ; src_x++) {
SkFixed xweight = s.getBitmapFilter()->lookup((srcPt.fX - src_x));
SkFixed combined_weight = SkFixedMul(xweight, yweight);
SkPMColor c = *s.fBitmap->getAddr32(src_x, src_y);
fr += combined_weight * SkGetPackedR32(c);
fg += combined_weight * SkGetPackedG32(c);
fb += combined_weight * SkGetPackedB32(c);
fa += combined_weight * SkGetPackedA32(c);
weight += combined_weight;
}
}
fr = SkFixedDiv(fr, weight);
fg = SkFixedDiv(fg, weight);
fb = SkFixedDiv(fb, weight);
fa = SkFixedDiv(fa, weight);
int a = SkClampMax(SkFixedRoundToInt(fa), 255);
int r = SkClampMax(SkFixedRoundToInt(fr), a);
int g = SkClampMax(SkFixedRoundToInt(fg), a);
int b = SkClampMax(SkFixedRoundToInt(fb), a);
*colors++ = SkPackARGB32(a, r, g, b);
x++;
}
}
SK_CONF_DECLARE(const char *, c_bitmapFilter, "bitmap.filter", "mitchell", "Which bitmap filter to use [mitchell, sinc, gaussian, triangle, box]");
static SkBitmapFilter *allocateBitmapFilter() {
if (!strcmp(c_bitmapFilter, "mitchell")) {
return SkNEW_ARGS(SkMitchellFilter,(1.f/3.f,1.f/3.f));
} else if (!strcmp(c_bitmapFilter, "sinc")) {
return SkNEW_ARGS(SkSincFilter,(3));
} else if (!strcmp(c_bitmapFilter, "gaussian")) {
return SkNEW_ARGS(SkGaussianFilter,(2));
} else if (!strcmp(c_bitmapFilter, "triangle")) {
return SkNEW(SkTriangleFilter);
} else if (!strcmp(c_bitmapFilter, "box")) {
return SkNEW(SkBoxFilter);
} else {
SkASSERT(!!!"Unknown filter type");
}
return NULL;
}
SkBitmapProcState::ShaderProc32
SkBitmapProcState::chooseBitmapFilterProc(const SkPaint& paint) {
// we need to be requested
uint32_t mask = SkPaint::kFilterBitmap_Flag
| SkPaint::kHighQualityFilterBitmap_Flag
;
if ((paint.getFlags() & mask) != mask) {
return NULL;
}
// TODO: consider supporting other configs (e.g. 565, A8)
if (fBitmap->config() != SkBitmap::kARGB_8888_Config) {
return NULL;
}
// TODO: consider supporting repeat and mirror
if (SkShader::kClamp_TileMode != fTileModeX || SkShader::kClamp_TileMode != fTileModeY) {
return NULL;
}
// TODO: support blending inside our procs
if (0xFF != paint.getAlpha()) {
return NULL;
}
if (fInvType & (SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask)) {
fBitmapFilter = allocateBitmapFilter();
}
if (fInvType & SkMatrix::kAffine_Mask) {
return highQualityFilter;
} else if (fInvType & SkMatrix::kScale_Mask) {
return highQualityFilter_ScaleOnly;
} else {
return NULL;
}
}
static void divideByWeights(SkFixed *sums, SkFixed *weights, SkBitmap *dst) {
for (int y = 0 ; y < dst->height() ; y++) {
for (int x = 0 ; x < dst->width() ; x++) {
SkFixed fr = SkFixedDiv(sums[4*(y*dst->width() + x) + 0], weights[y*dst->width() + x]);
SkFixed fg = SkFixedDiv(sums[4*(y*dst->width() + x) + 1], weights[y*dst->width() + x]);
SkFixed fb = SkFixedDiv(sums[4*(y*dst->width() + x) + 2], weights[y*dst->width() + x]);
SkFixed fa = SkFixedDiv(sums[4*(y*dst->width() + x) + 3], weights[y*dst->width() + x]);
int a = SkClampMax(SkFixedRoundToInt(fa), 255);
int r = SkClampMax(SkFixedRoundToInt(fr), a);
int g = SkClampMax(SkFixedRoundToInt(fg), a);
int b = SkClampMax(SkFixedRoundToInt(fb), a);
*dst->getAddr32(x,y) = SkPackARGB32(a, r, g, b);
}
}
}
static void upScaleHoriz(const SkBitmap *src, SkBitmap *dst, float scale, SkBitmapFilter *filter) {
for (int y = 0 ; y < src->height() ; y++) {
for (int x = 0 ; x < dst->width() ; x++) {
float sx = x / scale - 0.5f;
int x0 = SkClampMax(int(ceil(sx-filter->width() + 0.5f)), src->width()-1);
int x1 = SkClampMax(int(floor(sx+filter->width() + 0.5f)), src->width()-1);
SkFixed total_weight = 0;
SkFixed fr = 0, fg = 0, fb = 0, fa = 0;
for (int src_x = x0 ; src_x <= x1 ; src_x++) {
SkFixed weight = filter->lookup(sx - src_x);
SkPMColor c = *src->getAddr32(src_x,y);
fr += weight * SkGetPackedR32(c);
fg += weight * SkGetPackedG32(c);
fb += weight * SkGetPackedB32(c);
fa += weight * SkGetPackedA32(c);
total_weight += weight;
}
fr = SkFixedDiv(fr, total_weight);
fg = SkFixedDiv(fg, total_weight);
fb = SkFixedDiv(fb, total_weight);
fa = SkFixedDiv(fa, total_weight);
int a = SkClampMax(SkFixedRoundToInt(fa), 255);
int r = SkClampMax(SkFixedRoundToInt(fr), a);
int g = SkClampMax(SkFixedRoundToInt(fg), a);
int b = SkClampMax(SkFixedRoundToInt(fb), a);
*dst->getAddr32(x,y) = SkPackARGB32(a, r, g, b);
}
}
}
static void downScaleHoriz(const SkBitmap *src, SkBitmap *dst, float scale, SkBitmapFilter *filter) {
SkFixed *sums = SkNEW_ARRAY(SkFixed, dst->width() * dst->height() * 4);
SkFixed *weights = SkNEW_ARRAY(SkFixed, dst->width() * dst->height());
SkAutoTDeleteArray<SkFixed> ada1(sums);
SkAutoTDeleteArray<SkFixed> ada2(weights);
memset(sums, 0, dst->width() * dst->height() * sizeof(SkFixed) * 4);
memset(weights, 0, dst->width() * dst->height() * sizeof(SkFixed));
for (int y = 0 ; y < src->height() ; y++) {
for (int x = 0 ; x < src->width() ; x++) {
// splat each source pixel into the destination image
float dx = (x + 0.5f) * scale;
int x0 = SkClampMax(int(ceil(dx-filter->width() + 0.5f)), dst->width()-1);
int x1 = SkClampMax(int(floor(dx+filter->width() + 0.5f)), dst->width()-1);
SkPMColor c = *src->getAddr32(x,y);
for (int dst_x = x0 ; dst_x <= x1 ; dst_x++) {
SkFixed weight = filter->lookup(dx - dst_x);
sums[4*(y*dst->width() + dst_x) + 0] += weight*SkGetPackedR32(c);
sums[4*(y*dst->width() + dst_x) + 1] += weight*SkGetPackedG32(c);
sums[4*(y*dst->width() + dst_x) + 2] += weight*SkGetPackedB32(c);
sums[4*(y*dst->width() + dst_x) + 3] += weight*SkGetPackedA32(c);
weights[y*dst->width() + dst_x] += weight;
}
}
}
divideByWeights(sums, weights, dst);
}
static void upScaleVert(const SkBitmap *src, SkBitmap *dst, float scale, SkBitmapFilter *filter) {
for (int y = 0 ; y < dst->height() ; y++) {
for (int x = 0 ; x < dst->width() ; x++) {
float sy = y / scale - 0.5f;
int y0 = SkClampMax(int(ceil(sy-filter->width() + 0.5f)), src->height()-1);
int y1 = SkClampMax(int(floor(sy+filter->width() + 0.5f)), src->height()-1);
SkFixed total_weight = 0;
SkFixed fr = 0, fg = 0, fb = 0, fa = 0;
for (int src_y = y0 ; src_y <= y1 ; src_y++) {
SkFixed weight = filter->lookup(sy - src_y);
SkPMColor c = *src->getAddr32(x,src_y);
fr += weight * SkGetPackedR32(c);
fg += weight * SkGetPackedG32(c);
fb += weight * SkGetPackedB32(c);
fa += weight * SkGetPackedA32(c);
total_weight += weight;
}
fr = SkFixedDiv(fr, total_weight);
fg = SkFixedDiv(fg, total_weight);
fb = SkFixedDiv(fb, total_weight);
fa = SkFixedDiv(fa, total_weight);
int a = SkClampMax(SkFixedRoundToInt(fa), 255);
int r = SkClampMax(SkFixedRoundToInt(fr), a);
int g = SkClampMax(SkFixedRoundToInt(fg), a);
int b = SkClampMax(SkFixedRoundToInt(fb), a);
*dst->getAddr32(x,y) = SkPackARGB32(a, r, g, b);
}
}
}
static void downScaleVert(const SkBitmap *src, SkBitmap *dst, float scale, SkBitmapFilter *filter) {
SkFixed *sums = SkNEW_ARRAY(SkFixed, dst->width() * dst->height() * 4);
SkFixed *weights = SkNEW_ARRAY(SkFixed, dst->width() * dst->height());
SkAutoTDeleteArray<SkFixed> ada1(sums);
SkAutoTDeleteArray<SkFixed> ada2(weights);
memset(sums, 0, dst->width() * dst->height() * sizeof(SkFixed) * 4);
memset(weights, 0, dst->width() * dst->height() * sizeof(SkFixed));
for (int y = 0 ; y < src->height() ; y++) {
for (int x = 0 ; x < src->width() ; x++) {
// splat each source pixel into the destination image
float dy = (y + 0.5f) * scale;
int y0 = SkClampMax(int(ceil(dy-filter->width() + 0.5f)), dst->height()-1);
int y1 = SkClampMax(int(floor(dy+filter->width() + 0.5f)), dst->height()-1);
SkPMColor c = *src->getAddr32(x,y);
for (int dst_y = y0 ; dst_y <= y1 ; dst_y++) {
SkFixed weight = filter->lookup(dy - dst_y);
sums[4*(dst_y*dst->width() + x) + 0] += weight*SkGetPackedR32(c);
sums[4*(dst_y*dst->width() + x) + 1] += weight*SkGetPackedG32(c);
sums[4*(dst_y*dst->width() + x) + 2] += weight*SkGetPackedB32(c);
sums[4*(dst_y*dst->width() + x) + 3] += weight*SkGetPackedA32(c);
weights[dst_y*dst->width() + x] += weight;
}
}
}
divideByWeights(sums, weights, dst);
}
void SkBitmap::scale(SkBitmap *dst) const {
SkBitmap horiz_temp;
horiz_temp.setConfig(SkBitmap::kARGB_8888_Config, dst->width(), height());
horiz_temp.allocPixels();
SkBitmapFilter *filter = allocateBitmapFilter();
float horiz_scale = float(dst->width()) / width();
if (horiz_scale == 1) {
this->copyPixelsTo(horiz_temp.getPixels(), getSize());
} else if (horiz_scale > 1) {
upScaleHoriz(this, &horiz_temp, horiz_scale, filter);
} else if (horiz_scale < 1) {
downScaleHoriz(this, &horiz_temp, horiz_scale, filter);
}
float vert_scale = float(dst->height()) / height();
if (vert_scale == 1) {
horiz_temp.copyPixelsTo(dst->getPixels(), dst->getSize());
} else if (vert_scale > 1) {
upScaleVert(&horiz_temp, dst, vert_scale, filter);
} else if (vert_scale < 1) {
downScaleVert(&horiz_temp, dst, vert_scale, filter);
}
SkDELETE(filter);
}

150
src/core/SkBitmapFilter.h Normal file
Просмотреть файл

@ -0,0 +1,150 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkBitmapFilter_DEFINED
#define SkBitmapFilter_DEFINED
#include "SkMath.h"
// size of the precomputed bitmap filter tables for high quality filtering.
// Used to precompute the shape of the filter kernel.
// Table size chosen from experiments to see where I could start to see a difference.
#define SKBITMAP_FILTER_TABLE_SIZE 32
class SkBitmapFilter {
public:
SkBitmapFilter(float width)
: fWidth(width), fInvWidth(1.f/width) {
precomputed = false;
}
SkFixed lookup( float x ) const {
if (!precomputed) {
precomputeTable();
}
int filter_idx = int(fabsf(x * invWidth() * SKBITMAP_FILTER_TABLE_SIZE));
return fFilterTable[ SkTMin(filter_idx, SKBITMAP_FILTER_TABLE_SIZE-1) ];
}
float lookupFloat( float x ) const {
if (!precomputed) {
precomputeTable();
}
int filter_idx = int(fabsf(x * invWidth() * SKBITMAP_FILTER_TABLE_SIZE));
return fFilterTableFloat[ SkTMin(filter_idx, SKBITMAP_FILTER_TABLE_SIZE-1) ];
}
float width() const { return fWidth; }
float invWidth() const { return fInvWidth; }
virtual float evaluate(float x) const = 0;
virtual ~SkBitmapFilter() {}
protected:
float fWidth;
float fInvWidth;
mutable bool precomputed;
mutable SkFixed fFilterTable[SKBITMAP_FILTER_TABLE_SIZE];
mutable float fFilterTableFloat[SKBITMAP_FILTER_TABLE_SIZE];
private:
void precomputeTable() const {
precomputed = true;
SkFixed *ftp = fFilterTable;
float *ftp_float = fFilterTableFloat;
for (int x = 0; x < SKBITMAP_FILTER_TABLE_SIZE; ++x) {
float fx = ((float)x + .5f) * this->width() / SKBITMAP_FILTER_TABLE_SIZE;
float filter_value = evaluate(fx);
*ftp_float++ = filter_value;
*ftp++ = SkFloatToFixed(filter_value);
}
}
};
class SkMitchellFilter: public SkBitmapFilter {
public:
SkMitchellFilter(float b, float c, float width=2.0f)
: SkBitmapFilter(width), B(b), C(c) {
}
virtual float evaluate(float x) const SK_OVERRIDE {
x = fabsf(x);
if (x > 2.f) {
return 0;
} else if (x > 1.f) {
return ((-B - 6*C) * x*x*x + (6*B + 30*C) * x*x +
(-12*B - 48*C) * x + (8*B + 24*C)) * (1.f/6.f);
} else {
return ((12 - 9*B - 6*C) * x*x*x +
(-18 + 12*B + 6*C) * x*x +
(6 - 2*B)) * (1.f/6.f);
}
}
protected:
float B, C;
};
class SkGaussianFilter: public SkBitmapFilter {
public:
SkGaussianFilter(float a, float width=2.0f)
: SkBitmapFilter(width), alpha(a), expWidth(expf(-alpha * width * width)) {
}
virtual float evaluate(float x) const SK_OVERRIDE {
return SkTMax(0.f, float(expf(-alpha*x*x) - expWidth));
}
protected:
float alpha, expWidth;
};
class SkTriangleFilter: public SkBitmapFilter {
public:
SkTriangleFilter(float width=1)
: SkBitmapFilter(width) {
}
virtual float evaluate(float x) const SK_OVERRIDE {
return SkTMax(0.f, fWidth - fabsf(x));
}
protected:
};
class SkBoxFilter: public SkBitmapFilter {
public:
SkBoxFilter(float width=0.5f)
: SkBitmapFilter(width) {
}
virtual float evaluate(float x) const SK_OVERRIDE {
return 1;
}
protected:
};
class SkSincFilter: public SkBitmapFilter {
public:
SkSincFilter(float t, float width=3.f)
: SkBitmapFilter(width), tau(t) {
}
virtual float evaluate(float x) const SK_OVERRIDE {
x = sk_float_abs(x * fInvWidth);
if (x < 1e-5f) return 1.f;
if (x > 1.f) return 0.f;
x *= (float) M_PI;
float sinc = sk_float_sin(x) / x;
float lanczos = sk_float_sin(x * tau) / (x * tau);
return sinc * lanczos;
}
protected:
float tau;
};
#endif

Просмотреть файл

@ -1,187 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkBitmapProcState.h"
#include "SkBitmap.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkUnPreMultiply.h"
#include "SkRTConf.h"
#include "SkShader.h"
#define DS(x) SkDoubleToScalar(x)
#define MUL(a, b) ((a) * (b))
static inline SkPMColor cubicBlend(const SkFixed cc[4], SkPMColor c0, SkPMColor c1, SkPMColor c2, SkPMColor c3) {
SkFixed fa = MUL(cc[0], SkGetPackedA32(c0)) + MUL(cc[1], SkGetPackedA32(c1)) + MUL(cc[2], SkGetPackedA32(c2)) + MUL(cc[3], SkGetPackedA32(c3));
SkFixed fr = MUL(cc[0], SkGetPackedR32(c0)) + MUL(cc[1], SkGetPackedR32(c1)) + MUL(cc[2], SkGetPackedR32(c2)) + MUL(cc[3], SkGetPackedR32(c3));
SkFixed fg = MUL(cc[0], SkGetPackedG32(c0)) + MUL(cc[1], SkGetPackedG32(c1)) + MUL(cc[2], SkGetPackedG32(c2)) + MUL(cc[3], SkGetPackedG32(c3));
SkFixed fb = MUL(cc[0], SkGetPackedB32(c0)) + MUL(cc[1], SkGetPackedB32(c1)) + MUL(cc[2], SkGetPackedB32(c2)) + MUL(cc[3], SkGetPackedB32(c3));
int a = SkClampMax(SkFixedRoundToInt(fa), 255);
int r = SkClampMax(SkFixedRoundToInt(fr), a);
int g = SkClampMax(SkFixedRoundToInt(fg), a);
int b = SkClampMax(SkFixedRoundToInt(fb), a);
return SkPackARGB32(a, r, g, b);
}
static float poly_eval(const float cc[4], float t) {
return cc[0] + t * (cc[1] + t * (cc[2] + t * cc[3]));
}
static void build_coeff4(SkFixed dst[4], float t) {
static const SkScalar coefficients[16] = {
DS( 1.0 / 18.0), DS(-9.0 / 18.0), DS( 15.0 / 18.0), DS( -7.0 / 18.0),
DS(16.0 / 18.0), DS( 0.0 / 18.0), DS(-36.0 / 18.0), DS( 21.0 / 18.0),
DS( 1.0 / 18.0), DS( 9.0 / 18.0), DS( 27.0 / 18.0), DS(-21.0 / 18.0),
DS( 0.0 / 18.0), DS( 0.0 / 18.0), DS( -6.0 / 18.0), DS( 7.0 / 18.0),
};
dst[0] = SkFloatToFixed(poly_eval(&coefficients[ 0], t));
dst[1] = SkFloatToFixed(poly_eval(&coefficients[ 4], t));
dst[2] = SkFloatToFixed(poly_eval(&coefficients[ 8], t));
dst[3] = SkFloatToFixed(poly_eval(&coefficients[12], t));
}
static SkPMColor doBicubicFilter(const SkBitmap *bm, SkFixed coeffX[4], SkFixed coeffY[4],
int x0, int x1, int x2, int x3,
int y0, int y1, int y2, int y3 )
{
SkPMColor s00 = *bm->getAddr32(x0, y0);
SkPMColor s10 = *bm->getAddr32(x1, y0);
SkPMColor s20 = *bm->getAddr32(x2, y0);
SkPMColor s30 = *bm->getAddr32(x3, y0);
SkPMColor s0 = cubicBlend(coeffX, s00, s10, s20, s30);
SkPMColor s01 = *bm->getAddr32(x0, y1);
SkPMColor s11 = *bm->getAddr32(x1, y1);
SkPMColor s21 = *bm->getAddr32(x2, y1);
SkPMColor s31 = *bm->getAddr32(x3, y1);
SkPMColor s1 = cubicBlend(coeffX, s01, s11, s21, s31);
SkPMColor s02 = *bm->getAddr32(x0, y2);
SkPMColor s12 = *bm->getAddr32(x1, y2);
SkPMColor s22 = *bm->getAddr32(x2, y2);
SkPMColor s32 = *bm->getAddr32(x3, y2);
SkPMColor s2 = cubicBlend(coeffX, s02, s12, s22, s32);
SkPMColor s03 = *bm->getAddr32(x0, y3);
SkPMColor s13 = *bm->getAddr32(x1, y3);
SkPMColor s23 = *bm->getAddr32(x2, y3);
SkPMColor s33 = *bm->getAddr32(x3, y3);
SkPMColor s3 = cubicBlend(coeffX, s03, s13, s23, s33);
return cubicBlend(coeffY, s0, s1, s2, s3);
}
static void bicubicFilter(const SkBitmapProcState& s, int x, int y,
SkPMColor* SK_RESTRICT colors, int count) {
const int maxX = s.fBitmap->width() - 1;
const int maxY = s.fBitmap->height() - 1;
while (count-- > 0) {
SkPoint srcPt;
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x),
SkIntToScalar(y), &srcPt);
srcPt.fX -= SK_ScalarHalf;
srcPt.fY -= SK_ScalarHalf;
SkScalar fractx = srcPt.fX - SkScalarFloorToScalar(srcPt.fX);
SkScalar fracty = srcPt.fY - SkScalarFloorToScalar(srcPt.fY);
SkFixed coeffX[4], coeffY[4];
build_coeff4(coeffX, fractx);
build_coeff4(coeffY, fracty);
int sx = SkScalarFloorToInt(srcPt.fX);
int sy = SkScalarFloorToInt(srcPt.fY);
// Here is where we can support other tile modes (e.g. repeat or mirror)
int x0 = SkClampMax(sx - 1, maxX);
int x1 = SkClampMax(sx , maxX);
int x2 = SkClampMax(sx + 1, maxX);
int x3 = SkClampMax(sx + 2, maxX);
int y0 = SkClampMax(sy - 1, maxY);
int y1 = SkClampMax(sy , maxY);
int y2 = SkClampMax(sy + 1, maxY);
int y3 = SkClampMax(sy + 2, maxY);
*colors++ = doBicubicFilter( s.fBitmap, coeffX, coeffY, x0, x1, x2, x3, y0, y1, y2, y3 );
x++;
}
}
static void bicubicFilter_ScaleOnly(const SkBitmapProcState &s, int x, int y,
SkPMColor *SK_RESTRICT colors, int count) {
const int maxX = s.fBitmap->width() - 1;
const int maxY = s.fBitmap->height() - 1;
SkPoint srcPt;
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
srcPt.fY -= SK_ScalarHalf;
SkScalar fracty = srcPt.fY - SkScalarFloorToScalar(srcPt.fY);
SkFixed coeffX[4], coeffY[4];
build_coeff4(coeffY, fracty);
int sy = SkScalarFloorToInt(srcPt.fY);
int y0 = SkClampMax(sy - 1, maxY);
int y1 = SkClampMax(sy , maxY);
int y2 = SkClampMax(sy + 1, maxY);
int y3 = SkClampMax(sy + 2, maxY);
while (count-- > 0) {
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
srcPt.fX -= SK_ScalarHalf;
SkScalar fractx = srcPt.fX - SkScalarFloorToScalar(srcPt.fX);
build_coeff4(coeffX, fractx);
int sx = SkScalarFloorToInt(srcPt.fX);
// Here is where we can support other tile modes (e.g. repeat or mirror)
int x0 = SkClampMax(sx - 1, maxX);
int x1 = SkClampMax(sx , maxX);
int x2 = SkClampMax(sx + 1, maxX);
int x3 = SkClampMax(sx + 2, maxX);
*colors++ = doBicubicFilter( s.fBitmap, coeffX, coeffY, x0, x1, x2, x3, y0, y1, y2, y3 );
x++;
}
}
SkBitmapProcState::ShaderProc32
SkBitmapProcState::chooseBicubicFilterProc(const SkPaint& paint) {
// we need to be requested
uint32_t mask = SkPaint::kFilterBitmap_Flag
| SkPaint::kBicubicFilterBitmap_Flag
;
if ((paint.getFlags() & mask) != mask) {
return NULL;
}
// TODO: consider supporting other configs (e.g. 565, A8)
if (fBitmap->config() != SkBitmap::kARGB_8888_Config) {
return NULL;
}
// TODO: consider supporting repeat and mirror
if (SkShader::kClamp_TileMode != fTileModeX || SkShader::kClamp_TileMode != fTileModeY) {
return NULL;
}
// TODO: support blending inside our procs
if (0xFF != paint.getAlpha()) {
return NULL;
}
if (fInvType & SkMatrix::kAffine_Mask) {
return bicubicFilter;
} else if (fInvType & SkMatrix::kScale_Mask) {
return bicubicFilter_ScaleOnly;
} else {
return NULL;
}
}

Просмотреть файл

@ -302,13 +302,13 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
fShaderProc32 = this->chooseShaderProc32(); fShaderProc32 = this->chooseShaderProc32();
} }
if (NULL == fShaderProc32) {
fShaderProc32 = this->chooseBitmapFilterProc(paint);
}
// see if our platform has any accelerated overrides // see if our platform has any accelerated overrides
this->platformProcs(); this->platformProcs();
if (NULL == fShaderProc32) {
fShaderProc32 = this->chooseBicubicFilterProc(paint);
}
return true; return true;
} }

Просмотреть файл

@ -11,6 +11,7 @@
#define SkBitmapProcState_DEFINED #define SkBitmapProcState_DEFINED
#include "SkBitmap.h" #include "SkBitmap.h"
#include "SkBitmapFilter.h"
#include "SkMatrix.h" #include "SkMatrix.h"
#define FractionalInt_IS_64BIT #define FractionalInt_IS_64BIT
@ -113,6 +114,8 @@ struct SkBitmapProcState {
// are ignored // are ignored
ShaderProc32 getShaderProc32() const { return fShaderProc32; } ShaderProc32 getShaderProc32() const { return fShaderProc32; }
ShaderProc16 getShaderProc16() const { return fShaderProc16; } ShaderProc16 getShaderProc16() const { return fShaderProc16; }
SkBitmapFilter* getBitmapFilter() const { return fBitmapFilter; }
#ifdef SK_DEBUG #ifdef SK_DEBUG
MatrixProc getMatrixProc() const; MatrixProc getMatrixProc() const;
@ -139,12 +142,11 @@ private:
MatrixProc chooseMatrixProc(bool trivial_matrix); MatrixProc chooseMatrixProc(bool trivial_matrix);
bool chooseProcs(const SkMatrix& inv, const SkPaint&); bool chooseProcs(const SkMatrix& inv, const SkPaint&);
ShaderProc32 chooseShaderProc32(); ShaderProc32 chooseShaderProc32();
void buildFilterCoefficients(SkFixed dst[4], float t) const;
SkBitmapFilter *fBitmapFilter;
ShaderProc32 chooseBitmapFilterProc(const SkPaint &paint);
/** test method for choosing a bicubic shading filter
*/
ShaderProc32 chooseBicubicFilterProc(const SkPaint &paint);
// Return false if we failed to setup for fast translate (e.g. overflow) // Return false if we failed to setup for fast translate (e.g. overflow)
bool setupForTranslate(); bool setupForTranslate();
@ -200,4 +202,10 @@ void ClampX_ClampY_nofilter_affine(const SkBitmapProcState& s,
void S32_D16_filter_DX(const SkBitmapProcState& s, void S32_D16_filter_DX(const SkBitmapProcState& s,
const uint32_t* xy, int count, uint16_t* colors); const uint32_t* xy, int count, uint16_t* colors);
void highQualityFilter_ScaleOnly(const SkBitmapProcState &s, int x, int y,
SkPMColor *SK_RESTRICT colors, int count);
void highQualityFilter(const SkBitmapProcState &s, int x, int y,
SkPMColor *SK_RESTRICT colors, int count);
#endif #endif

Просмотреть файл

@ -0,0 +1,182 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkBitmapProcState.h"
#include "SkBitmap.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkUnPreMultiply.h"
#include "SkShader.h"
#include "SkBitmapFilter_opts_SSE2.h"
#include <emmintrin.h>
#if 0
static inline void print128i(__m128i value) {
int *v = (int*) &value;
printf("% .11d % .11d % .11d % .11d\n", v[0], v[1], v[2], v[3]);
}
static inline void print128i_16(__m128i value) {
short *v = (short*) &value;
printf("% .5d % .5d % .5d % .5d % .5d % .5d % .5d % .5d\n", v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
}
static inline void print128i_8(__m128i value) {
unsigned char *v = (unsigned char*) &value;
printf("%.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u %.3u\n",
v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7],
v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]
);
}
static inline void print128f(__m128 value) {
float *f = (float*) &value;
printf("%3.4f %3.4f %3.4f %3.4f\n", f[0], f[1], f[2], f[3]);
}
#endif
// because the border is handled specially, this is guaranteed to have all 16 pixels
// available to it without running off the bitmap's edge.
int debug_x = 20;
int debug_y = 255;
void highQualityFilter_SSE2(const SkBitmapProcState& s, int x, int y,
SkPMColor* SK_RESTRICT colors, int count) {
const int maxX = s.fBitmap->width() - 1;
const int maxY = s.fBitmap->height() - 1;
while (count-- > 0) {
SkPoint srcPt;
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x),
SkIntToScalar(y), &srcPt);
srcPt.fX -= SK_ScalarHalf;
srcPt.fY -= SK_ScalarHalf;
int sx = SkScalarFloorToInt(srcPt.fX);
int sy = SkScalarFloorToInt(srcPt.fY);
__m128 weight = _mm_setzero_ps();
__m128 accum = _mm_setzero_ps();
int y0 = SkTMax(0, int(ceil(sy-s.getBitmapFilter()->width() + 0.5f)));
int y1 = SkTMin(maxY, int(floor(sy+s.getBitmapFilter()->width() + 0.5f)));
int x0 = SkTMax(0, int(ceil(sx-s.getBitmapFilter()->width() + 0.5f)));
int x1 = SkTMin(maxX, int(floor(sx+s.getBitmapFilter()->width() + 0.5f)));
for (int src_y = y0; src_y <= y1; src_y++) {
float yweight = s.getBitmapFilter()->lookupFloat( (srcPt.fY - src_y) );
for (int src_x = x0; src_x <= x1 ; src_x++) {
float xweight = s.getBitmapFilter()->lookupFloat( (srcPt.fX - src_x) );
float combined_weight = xweight * yweight;
SkPMColor color = *s.fBitmap->getAddr32(src_x, src_y);
__m128i c = _mm_cvtsi32_si128( color );
c = _mm_unpacklo_epi8(c, _mm_setzero_si128());
c = _mm_unpacklo_epi16(c, _mm_setzero_si128());
__m128 cfloat = _mm_cvtepi32_ps( c );
__m128 weightVector = _mm_set1_ps(combined_weight);
accum = _mm_add_ps(accum, _mm_mul_ps(cfloat, weightVector));
weight = _mm_add_ps( weight, weightVector );
}
}
accum = _mm_div_ps(accum, weight);
accum = _mm_add_ps(accum, _mm_set1_ps(0.5f));
__m128i accumInt = _mm_cvtps_epi32( accum );
int localResult[4];
_mm_storeu_si128((__m128i *) (localResult), accumInt);
int a = SkClampMax(localResult[0], 255);
int r = SkClampMax(localResult[1], a);
int g = SkClampMax(localResult[2], a);
int b = SkClampMax(localResult[3], a);
*colors++ = SkPackARGB32(a, r, g, b);
x++;
}
}
void highQualityFilter_ScaleOnly_SSE2(const SkBitmapProcState &s, int x, int y,
SkPMColor *SK_RESTRICT colors, int count) {
const int maxX = s.fBitmap->width() - 1;
const int maxY = s.fBitmap->height() - 1;
SkPoint srcPt;
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x),
SkIntToScalar(y), &srcPt);
srcPt.fY -= SK_ScalarHalf;
int sy = SkScalarFloorToInt(srcPt.fY);
int y0 = SkTMax(0, int(ceil(sy-s.getBitmapFilter()->width() + 0.5f)));
int y1 = SkTMin(maxY, int(floor(sy+s.getBitmapFilter()->width() + 0.5f)));
while (count-- > 0) {
srcPt.fX -= SK_ScalarHalf;
srcPt.fY -= SK_ScalarHalf;
int sx = SkScalarFloorToInt(srcPt.fX);
float weight = 0;
__m128 accum = _mm_setzero_ps();
int x0 = SkTMax(0, int(ceil(sx-s.getBitmapFilter()->width() + 0.5f)));
int x1 = SkTMin(maxX, int(floor(sx+s.getBitmapFilter()->width() + 0.5f)));
for (int src_y = y0; src_y <= y1; src_y++) {
float yweight = s.getBitmapFilter()->lookupFloat( (srcPt.fY - src_y) );
for (int src_x = x0; src_x <= x1 ; src_x++) {
float xweight = s.getBitmapFilter()->lookupFloat( (srcPt.fX - src_x) );
float combined_weight = xweight * yweight;
SkPMColor color = *s.fBitmap->getAddr32(src_x, src_y);
__m128 c = _mm_set_ps(SkGetPackedB32(color),
SkGetPackedG32(color),
SkGetPackedR32(color),
SkGetPackedA32(color));
__m128 weightVector = _mm_set1_ps(combined_weight);
accum = _mm_add_ps(accum, _mm_mul_ps(c, weightVector));
weight += combined_weight;
}
}
__m128 totalWeightVector = _mm_set1_ps(weight);
accum = _mm_div_ps(accum, totalWeightVector);
accum = _mm_add_ps(accum, _mm_set1_ps(0.5f));
float localResult[4];
_mm_storeu_ps(localResult, accum);
int a = SkClampMax(int(localResult[0]), 255);
int r = SkClampMax(int(localResult[1]), a);
int g = SkClampMax(int(localResult[2]), a);
int b = SkClampMax(int(localResult[3]), a);
*colors++ = SkPackARGB32(a, r, g, b);
x++;
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x),
SkIntToScalar(y), &srcPt);
}
}

Просмотреть файл

@ -0,0 +1,20 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkBitmapFilter_opts_sse2_DEFINED
#define SkBitmapFilter_opts_sse2_DEFINED
#include "SkBitmapProcState.h"
void highQualityFilter_ScaleOnly_SSE2(const SkBitmapProcState &s, int x, int y,
SkPMColor *SK_RESTRICT colors, int count);
void highQualityFilter_SSE2(const SkBitmapProcState &s, int x, int y,
SkPMColor *SK_RESTRICT colors, int count);
#endif

Просмотреть файл

@ -7,6 +7,7 @@
#include "SkBitmapProcState_opts_SSE2.h" #include "SkBitmapProcState_opts_SSE2.h"
#include "SkBitmapProcState_opts_SSSE3.h" #include "SkBitmapProcState_opts_SSSE3.h"
#include "SkBitmapFilter_opts_SSE2.h"
#include "SkBlitMask.h" #include "SkBlitMask.h"
#include "SkBlitRow.h" #include "SkBlitRow.h"
#include "SkBlitRect_opts_SSE2.h" #include "SkBlitRect_opts_SSE2.h"
@ -14,6 +15,8 @@
#include "SkUtils_opts_SSE2.h" #include "SkUtils_opts_SSE2.h"
#include "SkUtils.h" #include "SkUtils.h"
#include "SkRTConf.h"
#if defined(_MSC_VER) && defined(_WIN64) #if defined(_MSC_VER) && defined(_WIN64)
#include <intrin.h> #include <intrin.h>
#endif #endif
@ -102,6 +105,8 @@ static bool cachedHasSSSE3() {
return gHasSSSE3; return gHasSSSE3;
} }
SK_CONF_DECLARE( bool, c_hqfilter_sse, "bitmap.filter.highQualitySSE", false, "Use SSE optimized version of high quality image filters");
void SkBitmapProcState::platformProcs() { void SkBitmapProcState::platformProcs() {
if (cachedHasSSSE3()) { if (cachedHasSSSE3()) {
#if !defined(SK_BUILD_FOR_ANDROID) #if !defined(SK_BUILD_FOR_ANDROID)
@ -142,6 +147,14 @@ void SkBitmapProcState::platformProcs() {
} else if (fMatrixProc == ClampX_ClampY_nofilter_affine) { } else if (fMatrixProc == ClampX_ClampY_nofilter_affine) {
fMatrixProc = ClampX_ClampY_nofilter_affine_SSE2; fMatrixProc = ClampX_ClampY_nofilter_affine_SSE2;
} }
if (c_hqfilter_sse) {
if (fShaderProc32 == highQualityFilter) {
fShaderProc32 = highQualityFilter_SSE2;
}
if (fShaderProc32 == highQualityFilter_ScaleOnly) {
fShaderProc32 = highQualityFilter_ScaleOnly_SSE2;
}
}
} }
} }