Swap over to using SkImageFilter::filterImage instead of filterImageDeprecated

This CL relies on https://codereview.chromium.org/1757983002/ (Add SkSpecialImage-based methods to SkImageFilter)

GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1762013002

TBR=bsalomon@google.com

Review URL: https://codereview.chromium.org/1762013002
This commit is contained in:
robertphillips 2016-03-07 12:45:14 -08:00 committed by Commit bot
parent 19de504eae
commit 4418dbac33
10 changed files with 419 additions and 195 deletions

View File

@ -137,20 +137,19 @@ public:
/**
* Request a new (result) image to be created from the src image.
* If the src has no pixels (isNull()) then the request just wants to
* receive the config and width/height of the result.
*
* The matrix is the current matrix on the canvas.
* The context contains the environment in which the filter is occurring.
* It includes the clip bounds, CTM and cache.
*
* Offset is the amount to translate the resulting image relative to the
* src when it is drawn. This is an out-param.
*
* If the result image cannot be created, return false, in which case both
* the result and offset parameters will be ignored by the caller.
* If the result image cannot be created, return null, in which case
* the offset parameters will be ignored by the caller.
*
* TODO: Right now the imagefilters sometimes return empty result bitmaps/
* specialimages. That doesn't seem quite right.
*/
bool filterImageDeprecated(Proxy*, const SkBitmap& src, const Context&,
SkBitmap* result, SkIPoint* offset) const;
SkSpecialImage* filterImage(SkSpecialImage* src, const Context&, SkIPoint* offset) const;
enum MapDirection {
@ -460,6 +459,9 @@ private:
friend class SkGraphics;
static void PurgeCache();
bool filterImageDeprecated(Proxy*, const SkBitmap& src, const Context&,
SkBitmap* result, SkIPoint* offset) const;
bool usesSrcInput() const { return fUsesSrcInput; }
typedef SkFlattenable INHERITED;

View File

@ -28,6 +28,7 @@
#include "SkReadPixelsRec.h"
#include "SkRRect.h"
#include "SkSmallAllocator.h"
#include "SkSpecialImage.h"
#include "SkSurface_Base.h"
#include "SkTextBlob.h"
#include "SkTextFormatParams.h"
@ -1392,19 +1393,29 @@ void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
SkIPoint pos = { x - iter.getX(), y - iter.getY() };
if (filter && !dstDev->canHandleImageFilter(filter)) {
SkImageFilter::DeviceProxy proxy(dstDev);
SkBitmap dst;
SkIPoint offset = SkIPoint::Make(0, 0);
const SkBitmap& src = srcDev->accessBitmap(false);
const SkBitmap& srcBM = srcDev->accessBitmap(false);
SkMatrix matrix = *iter.fMatrix;
matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
const SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
if (filter->filterImageDeprecated(&proxy, src, ctx, &dst, &offset)) {
SkAutoTUnref<SkSpecialImage> srcImg(SkSpecialImage::internal_fromBM(&proxy, srcBM));
if (!srcImg) {
continue; // something disastrous happened
}
SkAutoTUnref<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
if (resultImg) {
SkPaint tmpUnfiltered(*paint);
tmpUnfiltered.setImageFilter(nullptr);
dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tmpUnfiltered);
SkBitmap resultBM;
if (resultImg->internal_getBM(&resultBM)) {
// TODO: add drawSprite(SkSpecialImage) to SkDevice? (see skbug.com/5073)
dstDev->drawSprite(iter, resultBM, pos.x() + offset.x(), pos.y() + offset.y(),
tmpUnfiltered);
}
}
} else if (deviceIsBitmapDevice) {
const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;

View File

@ -17,6 +17,7 @@
#include "SkRasterClip.h"
#include "SkRSXform.h"
#include "SkShader.h"
#include "SkSpecialImage.h"
#include "SkTextBlobRunIterator.h"
#include "SkTextToPathIter.h"
@ -408,17 +409,27 @@ void SkBaseDevice::drawBitmapAsSprite(const SkDraw& draw, const SkBitmap& bitmap
SkImageFilter* filter = paint.getImageFilter();
if (filter && !this->canHandleImageFilter(filter)) {
SkImageFilter::DeviceProxy proxy(this);
SkBitmap dst;
SkIPoint offset = SkIPoint::Make(0, 0);
SkMatrix matrix = *draw.fMatrix;
matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
const SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-x, -y);
SkAutoTUnref<SkImageFilter::Cache> cache(this->getImageFilterCache());
SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
if (filter->filterImageDeprecated(&proxy, bitmap, ctx, &dst, &offset)) {
SkAutoTUnref<SkSpecialImage> srcImg(SkSpecialImage::internal_fromBM(&proxy, bitmap));
if (!srcImg) {
return; // something disastrous happened
}
SkAutoTUnref<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
if (resultImg) {
SkPaint tmpUnfiltered(paint);
tmpUnfiltered.setImageFilter(nullptr);
this->drawSprite(draw, dst, x + offset.x(), y + offset.y(), tmpUnfiltered);
SkBitmap resultBM;
if (resultImg->internal_getBM(&resultBM)) {
// TODO: add drawSprite(SkSpecialImage) to SkDevice? (see skbug.com/5073)
this->drawSprite(draw, resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered);
}
}
} else {
this->drawSprite(draw, bitmap, x, y, paint);

View File

@ -272,7 +272,20 @@ bool SkImageFilter::filterInputDeprecated(int index, Proxy* proxy, const SkBitma
if (!input) {
return true;
}
return input->filterImageDeprecated(proxy, src, this->mapContext(ctx), result, offset);
SkAutoTUnref<SkSpecialImage> specialSrc(SkSpecialImage::internal_fromBM(proxy, src));
if (!specialSrc) {
return false;
}
SkAutoTUnref<SkSpecialImage> tmp(input->onFilterImage(specialSrc,
this->mapContext(ctx),
offset));
if (!tmp) {
return false;
}
return tmp->internal_getBM(result);
}
bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst,
@ -327,9 +340,15 @@ bool SkImageFilter::canComputeFastBounds() const {
bool SkImageFilter::onFilterImageDeprecated(Proxy*, const SkBitmap&, const Context&,
SkBitmap*, SkIPoint*) const {
// Only classes that now use the new SkSpecialImage-based path will not have
// onFilterImageDeprecated methods. For those classes we should never be
// calling this method.
SkASSERT(0);
return false;
}
// SkImageFilter-derived classes that do not yet have their own onFilterImage
// implementation convert back to calling the deprecated filterImage method
SkSpecialImage* SkImageFilter::onFilterImage(SkSpecialImage* src, const Context& ctx,
SkIPoint* offset) const {
SkBitmap srcBM, resultBM;
@ -338,6 +357,7 @@ SkSpecialImage* SkImageFilter::onFilterImage(SkSpecialImage* src, const Context&
return nullptr;
}
// This is the only valid call to the old filterImage path
if (!this->filterImageDeprecated(src->internal_getProxy(), srcBM, ctx, &resultBM, offset)) {
return nullptr;
}
@ -583,27 +603,39 @@ bool SkImageFilter::filterInputGPUDeprecated(int index, SkImageFilter::Proxy* pr
if (!input) {
return true;
}
// Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity
// matrix with no clip and that the matrix, clip, and render target set before this function was
// called are restored before we return to the caller.
GrContext* context = src.getTexture()->getContext();
if (input->filterImageDeprecated(proxy, src, this->mapContext(ctx), result, offset)) {
if (!result->getTexture()) {
const SkImageInfo info = result->info();
if (kUnknown_SkColorType == info.colorType()) {
return false;
}
SkAutoTUnref<GrTexture> resultTex(
GrRefCachedBitmapTexture(context, *result, GrTextureParams::ClampNoFilter()));
if (!resultTex) {
return false;
}
result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref();
}
return true;
} else {
SkAutoTUnref<SkSpecialImage> specialSrc(SkSpecialImage::internal_fromBM(proxy, src));
if (!specialSrc) {
return false;
}
SkAutoTUnref<SkSpecialImage> tmp(input->onFilterImage(specialSrc,
this->mapContext(ctx),
offset));
if (!tmp) {
return false;
}
if (!tmp->internal_getBM(result)) {
return false;
}
if (!result->getTexture()) {
GrContext* context = src.getTexture()->getContext();
const SkImageInfo info = result->info();
if (kUnknown_SkColorType == info.colorType()) {
return false;
}
SkAutoTUnref<GrTexture> resultTex(
GrRefCachedBitmapTexture(context, *result, GrTextureParams::ClampNoFilter()));
if (!resultTex) {
return false;
}
result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref();
}
return true;
}
#endif

View File

@ -20,10 +20,12 @@ public:
virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
virtual bool onPeekPixels(SkPixmap*) const { return false; }
virtual bool testingOnlyOnPeekPixels(SkPixmap*) const { return false; }
virtual GrTexture* onPeekTexture() const { return nullptr; }
virtual bool testingOnlyOnGetROPixels(SkBitmap*) const = 0;
// Delete this entry point ASAP (see skbug.com/4965)
virtual bool getBitmap(SkBitmap* result) const = 0;
@ -42,14 +44,18 @@ void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPain
return as_SIB(this)->onDraw(canvas, x, y, paint);
}
bool SkSpecialImage::peekPixels(SkPixmap* pixmap) const {
return as_SIB(this)->onPeekPixels(pixmap);
bool SkSpecialImage::testingOnlyPeekPixels(SkPixmap* pixmap) const {
return as_SIB(this)->testingOnlyOnPeekPixels(pixmap);
}
GrTexture* SkSpecialImage::peekTexture() const {
return as_SIB(this)->onPeekTexture();
}
bool SkSpecialImage::testingOnlyGetROPixels(SkBitmap* result) const {
return as_SIB(this)->testingOnlyOnGetROPixels(result);
}
SkSpecialSurface* SkSpecialImage::newSurface(const SkImageInfo& info) const {
return as_SIB(this)->onNewSurface(info);
}
@ -125,7 +131,7 @@ public:
dst, paint, SkCanvas::kStrict_SrcRectConstraint);
}
bool onPeekPixels(SkPixmap* pixmap) const override {
bool testingOnlyOnPeekPixels(SkPixmap* pixmap) const override {
return fImage->peekPixels(pixmap);
}
@ -135,6 +141,10 @@ public:
return false;
}
bool testingOnlyOnGetROPixels(SkBitmap* result) const override {
return false;
}
SkSpecialSurface* onNewSurface(const SkImageInfo& info) const override {
#if SK_SUPPORT_GPU
GrTexture* texture = as_IB(fImage.get())->peekTexture();
@ -156,6 +166,11 @@ private:
#ifdef SK_DEBUG
static bool rect_fits(const SkIRect& rect, int width, int height) {
if (0 == width && 0 == height) {
SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom);
return true;
}
return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
rect.fRight >= 0 && rect.fRight <= width &&
rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
@ -178,7 +193,7 @@ public:
SkSpecialImage_Raster(SkImageFilter::Proxy* proxy, const SkIRect& subset, const SkBitmap& bm)
: INHERITED(proxy, subset, bm.getGenerationID())
, fBitmap(bm) {
if (bm.pixelRef()->isPreLocked()) {
if (bm.pixelRef() && bm.pixelRef()->isPreLocked()) {
// we only preemptively lock if there is no chance of triggering something expensive
// like a lazy decode or imagegenerator. PreLocked means it is flat pixels already.
fBitmap.lockPixels();
@ -199,7 +214,7 @@ public:
dst, paint, SkCanvas::kStrict_SrcRectConstraint);
}
bool onPeekPixels(SkPixmap* pixmap) const override {
bool testingOnlyOnPeekPixels(SkPixmap* pixmap) const override {
const SkImageInfo info = fBitmap.info();
if ((kUnknown_SkColorType == info.colorType()) || !fBitmap.getPixels()) {
return false;
@ -219,6 +234,11 @@ public:
return true;
}
bool testingOnlyOnGetROPixels(SkBitmap* result) const override {
*result = fBitmap;
return true;
}
SkSpecialSurface* onNewSurface(const SkImageInfo& info) const override {
return SkSpecialSurface::NewRaster(this->proxy(), info, nullptr);
}
@ -285,6 +305,25 @@ public:
return true;
}
bool testingOnlyOnGetROPixels(SkBitmap* result) const override {
const SkImageInfo info = SkImageInfo::MakeN32(this->width(),
this->height(),
this->isOpaque() ? kOpaque_SkAlphaType
: kPremul_SkAlphaType);
if (!result->tryAllocPixels(info)) {
return false;
}
if (!fTexture->readPixels(0, 0, result->width(), result->height(), kSkia8888_GrPixelConfig,
result->getPixels(), result->rowBytes())) {
return false;
}
result->pixelRef()->setImmutable();
return true;
}
SkSpecialSurface* onNewSurface(const SkImageInfo& info) const override {
GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(info);
desc.fFlags = kRenderTarget_GrSurfaceFlag;

View File

@ -72,6 +72,13 @@ public:
static SkSpecialImage* internal_fromBM(SkImageFilter::Proxy*, const SkBitmap&);
SkImageFilter::Proxy* internal_getProxy();
// TODO: hide this when GrLayerHoister uses SkSpecialImages more fully (see skbug.com/5063)
/**
* If the SpecialImage is backed by a gpu texture, return that texture.
* The active portion of the texture can be retrieved via 'subset'.
*/
GrTexture* peekTexture() const;
protected:
SkSpecialImage(SkImageFilter::Proxy* proxy, const SkIRect& subset, uint32_t uniqueID)
: fSubset(subset)
@ -94,13 +101,11 @@ protected:
*
* On failure, return false and ignore the pixmap parameter.
*/
bool peekPixels(SkPixmap*) const;
bool testingOnlyPeekPixels(SkPixmap*) const;
/**
* If the SpecialImage is backed by a gpu texture, return that texture.
* The active portion of the texture can be retrieved via 'subset'.
*/
GrTexture* peekTexture() const;
// This entry point is for testing only. It does a readback from VRAM for
// GPU-backed special images.
bool testingOnlyGetROPixels(SkBitmap*) const;
// TODO: remove this ASAP (see skbug.com/4965)
SkImageFilter::Proxy* proxy() const { return fProxy; }

View File

@ -14,6 +14,7 @@
#include "SkGpuDevice.h"
#include "SkLayerInfo.h"
#include "SkRecordDraw.h"
#include "SkSpecialImage.h"
#include "SkSurface.h"
#include "SkSurface_Gpu.h"
@ -285,18 +286,14 @@ void GrLayerHoister::FilterLayer(GrContext* context,
static const int kDefaultCacheSize = 32 * 1024 * 1024;
SkBitmap filteredBitmap;
SkIPoint offset = SkIPoint::Make(0, 0);
const SkIPoint filterOffset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop);
SkMatrix totMat = SkMatrix::I();
totMat.preConcat(info.fPreMat);
SkMatrix totMat(info.fPreMat);
totMat.preConcat(info.fLocalMat);
totMat.postTranslate(-SkIntToScalar(filterOffset.fX), -SkIntToScalar(filterOffset.fY));
SkASSERT(0 == layer->rect().fLeft && 0 == layer->rect().fTop);
SkIRect clipBounds = layer->rect();
const SkIRect& clipBounds = layer->rect();
// This cache is transient, and is freed (along with all its contained
// textures) when it goes out of scope.
@ -304,18 +301,24 @@ void GrLayerHoister::FilterLayer(GrContext* context,
SkImageFilter::Context filterContext(totMat, clipBounds, cache);
SkImageFilter::DeviceProxy proxy(device);
SkBitmap src;
GrWrapTextureInBitmap(layer->texture(), layer->texture()->width(), layer->texture()->height(),
false, &src);
if (!layer->filter()->filterImageDeprecated(&proxy, src, filterContext,
&filteredBitmap, &offset)) {
// TODO: should the layer hoister store stand alone layers as SkSpecialImages internally?
const SkIRect subset = SkIRect::MakeWH(layer->texture()->width(), layer->texture()->height());
SkAutoTUnref<SkSpecialImage> img(SkSpecialImage::NewFromGpu(&proxy, subset,
kNeedNewImageUniqueID_SpecialImage,
layer->texture()));
SkIPoint offset = SkIPoint::Make(0, 0);
SkAutoTUnref<SkSpecialImage> result(layer->filter()->filterImage(img,
filterContext,
&offset));
if (!result) {
// Filtering failed. Press on with the unfiltered version.
return;
}
SkIRect newRect = SkIRect::MakeWH(filteredBitmap.width(), filteredBitmap.height());
layer->setTexture(filteredBitmap.getTexture(), newRect, false);
SkASSERT(result->peekTexture());
layer->setTexture(result->peekTexture(), result->subset(), false);
layer->setOffset(offset);
}

View File

@ -32,11 +32,14 @@
#include "SkPoint3.h"
#include "SkReadBuffer.h"
#include "SkRect.h"
#include "SkSpecialImage.h"
#include "SkSpecialSurface.h"
#include "SkSurface.h"
#include "SkTableColorFilter.h"
#include "SkTileImageFilter.h"
#include "SkXfermodeImageFilter.h"
#include "Test.h"
#include "TestingSpecialImageAccess.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
@ -155,6 +158,35 @@ static SkImageFilter* make_blue(SkImageFilter* input, const SkImageFilter::CropR
return SkColorFilterImageFilter::Create(filter, input, cropRect);
}
static SkSpecialImage* create_empty_special_image(GrContext* context,
SkImageFilter::Proxy* proxy,
int widthHeight) {
SkAutoTUnref<SkSpecialSurface> surf;
if (context) {
GrSurfaceDesc desc;
desc.fConfig = kSkia8888_GrPixelConfig;
desc.fFlags = kRenderTarget_GrSurfaceFlag;
desc.fWidth = widthHeight;
desc.fHeight = widthHeight;
surf.reset(SkSpecialSurface::NewRenderTarget(proxy, context, desc));
} else {
const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
kOpaque_SkAlphaType);
surf.reset(SkSpecialSurface::NewRaster(proxy, info));
}
SkASSERT(surf);
SkCanvas* canvas = surf->getCanvas();
SkASSERT(canvas);
canvas->clear(0x0);
return surf->newImageSnapshot();
}
DEF_TEST(ImageFilter, reporter) {
{
// Check that two non-clipping color-matrice-filters concatenate into a single filter.
@ -271,13 +303,14 @@ DEF_TEST(ImageFilter, reporter) {
}
}
static void test_crop_rects(SkImageFilter::Proxy* proxy, skiatest::Reporter* reporter) {
static void test_crop_rects(SkImageFilter::Proxy* proxy,
skiatest::Reporter* reporter,
GrContext* context) {
// Check that all filters offset to their absolute crop rect,
// unaffected by the input crop rect.
// Tests pass by not asserting.
SkBitmap bitmap;
bitmap.allocN32Pixels(100, 100);
bitmap.eraseARGB(0, 0, 0, 0);
SkAutoTUnref<SkSpecialImage> srcImg(create_empty_special_image(context, proxy, 100));
SkASSERT(srcImg);
SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
@ -316,15 +349,12 @@ static void test_crop_rects(SkImageFilter::Proxy* proxy, skiatest::Reporter* rep
for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
SkImageFilter* filter = filters[i];
SkBitmap result;
SkIPoint offset;
SkString str;
str.printf("filter %d", static_cast<int>(i));
SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
REPORTER_ASSERT_MESSAGE(reporter,
filter->filterImageDeprecated(proxy, bitmap, ctx,
&result, &offset),
str.c_str());
SkAutoTUnref<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
REPORTER_ASSERT_MESSAGE(reporter, resultImg, str.c_str());
REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str());
}
@ -354,7 +384,11 @@ static SkBitmap make_gradient_circle(int width, int height) {
return bitmap;
}
static void test_negative_blur_sigma(SkImageFilter::Proxy* proxy, skiatest::Reporter* reporter) {
static void test_negative_blur_sigma(SkImageFilter::Proxy* proxy,
skiatest::Reporter* reporter,
GrContext* context) {
// Check that SkBlurImageFilter will accept a negative sigma, either in
// the given arguments or after CTM application.
const int width = 32, height = 32;
@ -364,41 +398,65 @@ static void test_negative_blur_sigma(SkImageFilter::Proxy* proxy, skiatest::Repo
SkAutoTUnref<SkImageFilter> negativeFilter(SkBlurImageFilter::Create(-five, five));
SkBitmap gradient = make_gradient_circle(width, height);
SkBitmap positiveResult1, negativeResult1;
SkBitmap positiveResult2, negativeResult2;
SkAutoTUnref<SkSpecialImage> imgSrc(SkSpecialImage::NewFromRaster(proxy,
SkIRect::MakeWH(width,
height),
gradient));
SkIPoint offset;
SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
REPORTER_ASSERT(reporter,
positiveFilter->filterImageDeprecated(proxy, gradient, ctx,
&positiveResult1, &offset));
REPORTER_ASSERT(reporter,
negativeFilter->filterImageDeprecated(proxy, gradient, ctx,
&negativeResult1, &offset));
SkAutoTUnref<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc, ctx, &offset));
REPORTER_ASSERT(reporter, positiveResult1);
SkAutoTUnref<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc, ctx, &offset));
REPORTER_ASSERT(reporter, negativeResult1);
SkMatrix negativeScale;
negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr);
REPORTER_ASSERT(reporter,
positiveFilter->filterImageDeprecated(proxy, gradient, negativeCTX,
&negativeResult2, &offset));
REPORTER_ASSERT(reporter,
negativeFilter->filterImageDeprecated(proxy, gradient, negativeCTX,
&positiveResult2, &offset));
SkAutoLockPixels lockP1(positiveResult1);
SkAutoLockPixels lockP2(positiveResult2);
SkAutoLockPixels lockN1(negativeResult1);
SkAutoLockPixels lockN2(negativeResult2);
SkAutoTUnref<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc,
negativeCTX,
&offset));
REPORTER_ASSERT(reporter, negativeResult2);
SkAutoTUnref<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc,
negativeCTX,
&offset));
REPORTER_ASSERT(reporter, positiveResult2);
SkBitmap positiveResultBM1, positiveResultBM2;
SkBitmap negativeResultBM1, negativeResultBM2;
TestingSpecialImageAccess::GetROPixels(positiveResult1, &positiveResultBM1);
TestingSpecialImageAccess::GetROPixels(positiveResult2, &positiveResultBM2);
TestingSpecialImageAccess::GetROPixels(negativeResult1, &negativeResultBM1);
TestingSpecialImageAccess::GetROPixels(negativeResult2, &negativeResultBM2);
SkAutoLockPixels lockP1(positiveResultBM1);
SkAutoLockPixels lockP2(positiveResultBM2);
SkAutoLockPixels lockN1(negativeResultBM1);
SkAutoLockPixels lockN2(negativeResultBM2);
for (int y = 0; y < height; y++) {
int diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult1.getAddr32(0, y), positiveResult1.rowBytes());
int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
negativeResultBM1.getAddr32(0, y),
positiveResultBM1.rowBytes());
REPORTER_ASSERT(reporter, !diffs);
if (diffs) {
break;
}
diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult2.getAddr32(0, y), positiveResult1.rowBytes());
diffs = memcmp(positiveResultBM1.getAddr32(0, y),
negativeResultBM2.getAddr32(0, y),
positiveResultBM1.rowBytes());
REPORTER_ASSERT(reporter, !diffs);
if (diffs) {
break;
}
diffs = memcmp(positiveResult1.getAddr32(0, y), positiveResult2.getAddr32(0, y), positiveResult1.rowBytes());
diffs = memcmp(positiveResultBM1.getAddr32(0, y),
positiveResultBM2.getAddr32(0, y),
positiveResultBM1.rowBytes());
REPORTER_ASSERT(reporter, !diffs);
if (diffs) {
break;
@ -406,16 +464,53 @@ static void test_negative_blur_sigma(SkImageFilter::Proxy* proxy, skiatest::Repo
}
}
DEF_TEST(TestNegativeBlurSigma, reporter) {
const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
typedef void (*PFTest)(SkImageFilter::Proxy* proxy,
skiatest::Reporter* reporter,
GrContext* context);
static void run_raster_test(skiatest::Reporter* reporter,
int widthHeight,
PFTest test) {
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
const SkImageInfo info = SkImageInfo::MakeN32Premul(widthHeight, widthHeight);
SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props));
SkImageFilter::DeviceProxy proxy(device);
test_negative_blur_sigma(&proxy, reporter);
(*test)(&proxy, reporter, nullptr);
}
#if SK_SUPPORT_GPU
static void run_gpu_test(skiatest::Reporter* reporter,
GrContext* context,
int widthHeight,
PFTest test) {
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
SkBudgeted::kNo,
SkImageInfo::MakeN32Premul(widthHeight,
widthHeight),
0,
&props,
SkGpuDevice::kUninit_InitContents));
SkImageFilter::DeviceProxy proxy(device);
(*test)(&proxy, reporter, context);
}
#endif
DEF_TEST(TestNegativeBlurSigma, reporter) {
run_raster_test(reporter, 100, test_negative_blur_sigma);
}
#if SK_SUPPORT_GPU
DEF_GPUTEST_FOR_NATIVE_CONTEXT(TestNegativeBlurSigma_Gpu, reporter, context) {
run_gpu_test(reporter, context, 100, test_negative_blur_sigma);
}
#endif
DEF_TEST(ImageFilterDrawTiled, reporter) {
// Check that all filters when drawn tiled (with subsequent clip rects) exactly
// match the same filters drawn with a single full-canvas bitmap draw.
@ -654,7 +749,9 @@ DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
}
DEF_TEST(ImageFilterMergeResultSize, reporter) {
static void test_imagefilter_merge_result_size(SkImageFilter::Proxy* proxy,
skiatest::Reporter* reporter,
GrContext* context) {
SkBitmap greenBM;
greenBM.allocN32Pixels(20, 20);
greenBM.eraseColor(SK_ColorGREEN);
@ -662,20 +759,27 @@ DEF_TEST(ImageFilterMergeResultSize, reporter) {
SkAutoTUnref<SkImageFilter> source(SkImageSource::Create(greenImage.get()));
SkAutoTUnref<SkImageFilter> merge(SkMergeImageFilter::Create(source.get(), source.get()));
SkBitmap bitmap;
bitmap.allocN32Pixels(1, 1);
bitmap.eraseColor(0);
const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props));
SkImageFilter::DeviceProxy proxy(device);
SkAutoTUnref<SkSpecialImage> srcImg(create_empty_special_image(context, proxy, 1));
SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr);
SkBitmap result;
SkIPoint offset;
REPORTER_ASSERT(reporter, merge->filterImageDeprecated(&proxy, bitmap, ctx, &result, &offset));
REPORTER_ASSERT(reporter, result.width() == 20 && result.height() == 20);
SkAutoTUnref<SkSpecialImage> resultImg(merge->filterImage(srcImg, ctx, &offset));
REPORTER_ASSERT(reporter, resultImg);
REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
}
DEF_TEST(ImageFilterMergeResultSize, reporter) {
run_raster_test(reporter, 100, test_imagefilter_merge_result_size);
}
#if SK_SUPPORT_GPU
DEF_GPUTEST_FOR_NATIVE_CONTEXT(ImageFilterMergeResultSize_Gpu, reporter, context) {
run_gpu_test(reporter, context, 100, test_imagefilter_merge_result_size);
}
#endif
static void draw_blurred_rect(SkCanvas* canvas) {
SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(SkIntToScalar(8), 0));
SkPaint filterPaint;
@ -803,15 +907,15 @@ DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
}
DEF_TEST(ImageFilterCropRect, reporter) {
const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props));
SkImageFilter::DeviceProxy proxy(device);
test_crop_rects(&proxy, reporter);
run_raster_test(reporter, 100, test_crop_rects);
}
#if SK_SUPPORT_GPU
DEF_GPUTEST_FOR_NATIVE_CONTEXT(ImageFilterCropRect_Gpu, reporter, context) {
run_gpu_test(reporter, context, 100, test_crop_rects);
}
#endif
DEF_TEST(ImageFilterMatrix, reporter) {
SkBitmap temp;
temp.allocN32Pixels(100, 100);
@ -901,31 +1005,44 @@ DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
}
DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
SkRTreeFactory factory;
SkPictureRecorder recorder;
SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
static void test_clipped_picture_imagefilter(SkImageFilter::Proxy* proxy,
skiatest::Reporter* reporter,
GrContext* context) {
SkAutoTUnref<SkPicture> picture;
// Create an SkPicture which simply draws a green 1x1 rectangle.
SkPaint greenPaint;
greenPaint.setColor(SK_ColorGREEN);
recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
SkAutoTUnref<SkPicture> picture(recorder.endRecording());
{
SkRTreeFactory factory;
SkPictureRecorder recorder;
SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
// Create an SkPicture which simply draws a green 1x1 rectangle.
SkPaint greenPaint;
greenPaint.setColor(SK_ColorGREEN);
recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
picture.reset(recorder.endRecording());
}
SkAutoTUnref<SkSpecialImage> srcImg(create_empty_special_image(context, proxy, 2));
SkAutoTUnref<SkImageFilter> imageFilter(SkPictureImageFilter::Create(picture.get()));
SkBitmap result;
SkIPoint offset;
SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr);
SkBitmap bitmap;
bitmap.allocN32Pixels(2, 2);
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
SkBitmapDevice device(bitmap, props);
SkImageFilter::DeviceProxy proxy(&device);
REPORTER_ASSERT(reporter,
!imageFilter->filterImageDeprecated(&proxy, bitmap, ctx, &result, &offset));
SkAutoTUnref<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg, ctx, &offset));
REPORTER_ASSERT(reporter, !resultImage);
}
DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
run_raster_test(reporter, 2, test_clipped_picture_imagefilter);
}
#if SK_SUPPORT_GPU
DEF_GPUTEST_FOR_NATIVE_CONTEXT(ImageFilterClippedPictureImageFilter_Gpu, reporter, context) {
run_gpu_test(reporter, context, 2, test_clipped_picture_imagefilter);
}
#endif
DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
// Even when there's an empty saveLayer()/restore(), ensure that an image
// filter or color filter which affects transparent black still draws.
@ -1154,13 +1271,10 @@ DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
test_xfermode_cropped_input(&canvas, reporter);
}
DEF_TEST(ComposedImageFilterOffset, reporter) {
SkBitmap bitmap;
bitmap.allocN32Pixels(100, 100);
bitmap.eraseARGB(0, 0, 0, 0);
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
SkBitmapDevice device(bitmap, props);
SkImageFilter::DeviceProxy proxy(&device);
static void test_composed_imagefilter_offset(SkImageFilter::Proxy* proxy,
skiatest::Reporter* reporter,
GrContext* context) {
SkAutoTUnref<SkSpecialImage> srcImg(create_empty_special_image(context, proxy, 100));
SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
SkAutoTUnref<SkImageFilter> offsetFilter(SkOffsetImageFilter::Create(0, 0, nullptr, &cropRect));
@ -1168,36 +1282,54 @@ DEF_TEST(ComposedImageFilterOffset, reporter) {
nullptr, &cropRect));
SkAutoTUnref<SkImageFilter> composedFilter(SkComposeImageFilter::Create(blurFilter,
offsetFilter.get()));
SkBitmap result;
SkIPoint offset;
SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
REPORTER_ASSERT(reporter,
composedFilter->filterImageDeprecated(&proxy, bitmap, ctx, &result, &offset));
SkAutoTUnref<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg, ctx, &offset));
REPORTER_ASSERT(reporter, resultImg);
REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
}
DEF_TEST(PartialCropRect, reporter) {
SkBitmap bitmap;
bitmap.allocN32Pixels(100, 100);
bitmap.eraseARGB(0, 0, 0, 0);
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
SkBitmapDevice device(bitmap, props);
SkImageFilter::DeviceProxy proxy(&device);
DEF_TEST(ComposedImageFilterOffset, reporter) {
run_raster_test(reporter, 100, test_composed_imagefilter_offset);
}
#if SK_SUPPORT_GPU
DEF_GPUTEST_FOR_NATIVE_CONTEXT(ComposedImageFilterOffset_Gpu, reporter, context) {
run_gpu_test(reporter, context, 100, test_composed_imagefilter_offset);
}
#endif
static void test_partial_crop_rect(SkImageFilter::Proxy* proxy,
skiatest::Reporter* reporter,
GrContext* context) {
SkAutoTUnref<SkSpecialImage> srcImg(create_empty_special_image(context, proxy, 100));
SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
SkAutoTUnref<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
SkBitmap result;
SkIPoint offset;
SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
REPORTER_ASSERT(reporter,
filter->filterImageDeprecated(&proxy, bitmap, ctx, &result, &offset));
SkAutoTUnref<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
REPORTER_ASSERT(reporter, resultImg);
REPORTER_ASSERT(reporter, offset.fX == 0);
REPORTER_ASSERT(reporter, offset.fY == 0);
REPORTER_ASSERT(reporter, result.width() == 20);
REPORTER_ASSERT(reporter, result.height() == 30);
REPORTER_ASSERT(reporter, resultImg->width() == 20);
REPORTER_ASSERT(reporter, resultImg->height() == 30);
}
DEF_TEST(PartialCropRect, reporter) {
run_raster_test(reporter, 100, test_partial_crop_rect);
}
#if SK_SUPPORT_GPU
DEF_GPUTEST_FOR_NATIVE_CONTEXT(PartialCropRect_Gpu, reporter, context) {
run_gpu_test(reporter, context, 100, test_partial_crop_rect);
}
#endif
DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
@ -1325,20 +1457,6 @@ DEF_TEST(BlurLargeImage, reporter) {
#if SK_SUPPORT_GPU
DEF_GPUTEST_FOR_NATIVE_CONTEXT(ImageFilterCropRect_Gpu, reporter, context) {
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
SkBudgeted::kNo,
SkImageInfo::MakeN32Premul(100, 100),
0,
&props,
SkGpuDevice::kUninit_InitContents));
SkImageFilter::DeviceProxy proxy(device);
test_crop_rects(&proxy, reporter);
}
DEF_GPUTEST_FOR_NATIVE_CONTEXT(HugeBlurImageFilter_Gpu, reporter, context) {
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
@ -1367,20 +1485,6 @@ DEF_GPUTEST_FOR_NATIVE_CONTEXT(XfermodeImageFilterCroppedInput_Gpu, reporter, co
test_xfermode_cropped_input(&canvas, reporter);
}
DEF_GPUTEST_FOR_NATIVE_CONTEXT(TestNegativeBlurSigma_Gpu, reporter, context) {
const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
SkBudgeted::kNo,
SkImageInfo::MakeN32Premul(1, 1),
0,
&props,
SkGpuDevice::kUninit_InitContents));
SkImageFilter::DeviceProxy proxy(device);
test_negative_blur_sigma(&proxy, reporter);
}
DEF_GPUTEST_FOR_ALL_CONTEXTS(BlurLargeImage_Gpu, reporter, context) {
SkAutoTUnref<SkSurface> surface(
SkSurface::NewRenderTarget(context, SkBudgeted::kYes,

View File

@ -11,25 +11,12 @@
#include "SkSpecialImage.h"
#include "SkSpecialSurface.h"
#include "Test.h"
#include "TestingSpecialImageAccess.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
#endif
class TestingSpecialImageAccess {
public:
static const SkIRect& Subset(const SkSpecialImage* img) {
return img->subset();
}
static bool PeekPixels(const SkSpecialImage* img, SkPixmap* pixmap) {
return img->peekPixels(pixmap);
}
static GrTexture* PeekTexture(const SkSpecialImage* img) {
return img->peekTexture();
}
};
// This test creates backing resources exactly sized to [kFullSize x kFullSize].
// It then wraps them in an SkSpecialImage with only the center (red) region being active.

View File

@ -0,0 +1,30 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file
*/
#ifndef TestingSpecialImageAccess_DEFINED
#define TestingSpecialImageAccess_DEFINED
class TestingSpecialImageAccess {
public:
static const SkIRect& Subset(const SkSpecialImage* img) {
return img->subset();
}
static bool PeekPixels(const SkSpecialImage* img, SkPixmap* pixmap) {
return img->testingOnlyPeekPixels(pixmap);
}
static GrTexture* PeekTexture(const SkSpecialImage* img) {
return img->peekTexture();
}
static bool GetROPixels(const SkSpecialImage* img, SkBitmap* result) {
return img->testingOnlyGetROPixels(result);
}
};
#endif