aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar senorblanco <senorblanco@chromium.org>2015-03-28 13:43:14 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-03-28 13:43:14 -0700
commitb97dafefe63ea0a1bbce8e8b209f4920983fb8b9 (patch)
tree069e7aa4d234b37b86c08b5aa30a712b81f7a45f
parentd8b34c26c2a2f8e37e0cc9a7910306aecacadd92 (diff)
Implement approx-match support in image filter saveLayer() offscreen.
Currently, the GPU-side image filter implementation creates exact-match textures for the offscreen backing stores for saveLayer(). This is because several filters have GPU implementations which depend on the texture coordinates being 0..1. The fix is three-fold: 1) Store the actual requested size in the SkGpuDevice, so that when wrapping it in an SkBitmap for passing to filterImage(), we can give it the original size. 2) Fix the filters (SkMagnifierImageFilter, more TBD) whose GPU implementation depends on 0..1 texture coordinates. 3) Remove the exception for GPU-side image filters in SkCanvas::internalSaveLayer(). N.B.: this change will cause some minor pixel diffs in the GPU results of the following GMs (and possibly more): matriximagefilter, matrixconvolution, imagefiltersscaled, lighting, imagemagnifier, filterfastbounds, complexclip_aa_Layer_invert, complexclip_aa_layer, complexclip_bw_layer_invert, complexclip_bw_layer. BUG=skia:3532 Review URL: https://codereview.chromium.org/1034733002
-rw-r--r--src/core/SkCanvas.cpp8
-rw-r--r--src/effects/SkMagnifierImageFilter.cpp46
-rw-r--r--src/gpu/SkGpuDevice.cpp34
-rw-r--r--src/gpu/SkGpuDevice.h13
4 files changed, 67 insertions, 34 deletions
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 8426f090ec..5310c9f7d5 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -936,14 +936,6 @@ void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Sav
}
SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
-#if 1
- // this seems needed for current GMs, but makes us draw slower on the GPU
- // Related to https://code.google.com/p/skia/issues/detail?id=3519 ?
- //
- if (paint && paint->getImageFilter()) {
- usage = SkBaseDevice::kPossible_TileUsage;
- }
-#endif
device = device->onCreateDevice(SkBaseDevice::CreateInfo(info, usage, geo), paint);
if (NULL == device) {
SkErrorInternals::SetError( kInternalError_SkError,
diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp
index 622713d796..d8e21cf29a 100644
--- a/src/effects/SkMagnifierImageFilter.cpp
+++ b/src/effects/SkMagnifierImageFilter.cpp
@@ -25,6 +25,7 @@ class GrMagnifierEffect : public GrSingleTextureEffect {
public:
static GrFragmentProcessor* Create(GrTexture* texture,
+ const SkRect& bounds,
float xOffset,
float yOffset,
float xInvZoom,
@@ -32,6 +33,7 @@ public:
float xInvInset,
float yInvInset) {
return SkNEW_ARGS(GrMagnifierEffect, (texture,
+ bounds,
xOffset,
yOffset,
xInvZoom,
@@ -48,6 +50,7 @@ public:
GrGLFragmentProcessor* createGLInstance() const override;
+ const SkRect& bounds() const { return fBounds; }
float x_offset() const { return fXOffset; }
float y_offset() const { return fYOffset; }
float x_inv_zoom() const { return fXInvZoom; }
@@ -57,6 +60,7 @@ public:
private:
GrMagnifierEffect(GrTexture* texture,
+ const SkRect& bounds,
float xOffset,
float yOffset,
float xInvZoom,
@@ -64,6 +68,7 @@ private:
float xInvInset,
float yInvInset)
: GrSingleTextureEffect(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
+ , fBounds(bounds)
, fXOffset(xOffset)
, fYOffset(yOffset)
, fXInvZoom(xInvZoom)
@@ -79,6 +84,7 @@ private:
GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
+ SkRect fBounds;
float fXOffset;
float fYOffset;
float fXInvZoom;
@@ -109,6 +115,7 @@ private:
UniformHandle fOffsetVar;
UniformHandle fInvZoomVar;
UniformHandle fInvInsetVar;
+ UniformHandle fBoundsVar;
typedef GrGLFragmentProcessor INHERITED;
};
@@ -134,6 +141,10 @@ void GrGLMagnifierEffect::emitCode(GrGLFPBuilder* builder,
GrGLProgramBuilder::kFragment_Visibility |
GrGLProgramBuilder::kVertex_Visibility,
kVec2f_GrSLType, kDefault_GrSLPrecision, "InvInset");
+ fBoundsVar = builder->addUniform(
+ GrGLProgramBuilder::kFragment_Visibility |
+ GrGLProgramBuilder::kVertex_Visibility,
+ kVec4f_GrSLType, kDefault_GrSLPrecision, "Bounds");
GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
@@ -142,9 +153,9 @@ void GrGLMagnifierEffect::emitCode(GrGLFPBuilder* builder,
builder->getUniformCStr(fOffsetVar),
coords2D.c_str(),
builder->getUniformCStr(fInvZoomVar));
-
- fsBuilder->codeAppend("\t\tvec2 delta = min(coord, vec2(1.0, 1.0) - coord);\n");
-
+ const char* bounds = builder->getUniformCStr(fBoundsVar);
+ fsBuilder->codeAppendf("\t\tvec2 delta = (coord - %s.xy) * %s.zw;\n", bounds, bounds);
+ fsBuilder->codeAppendf("\t\tdelta = min(delta, vec2(1.0, 1.0) - delta);\n");
fsBuilder->codeAppendf("\t\tdelta = delta * %s;\n", builder->getUniformCStr(fInvInsetVar));
fsBuilder->codeAppend("\t\tfloat weight = 0.0;\n");
@@ -175,6 +186,8 @@ void GrGLMagnifierEffect::setData(const GrGLProgramDataManager& pdman,
pdman.set2f(fOffsetVar, zoom.x_offset(), zoom.y_offset());
pdman.set2f(fInvZoomVar, zoom.x_inv_zoom(), zoom.y_inv_zoom());
pdman.set2f(fInvInsetVar, zoom.x_inv_inset(), zoom.y_inv_inset());
+ pdman.set4f(fBoundsVar, zoom.bounds().x(), zoom.bounds().y(),
+ zoom.bounds().width(), zoom.bounds().height());
}
/////////////////////////////////////////////////////////////////////
@@ -206,6 +219,7 @@ GrFragmentProcessor* GrMagnifierEffect::TestCreate(SkRandom* random,
GrFragmentProcessor* effect = GrMagnifierEffect::Create(
texture,
+ SkRect::MakeWH(SkIntToScalar(kMaxWidth), SkIntToScalar(kMaxHeight)),
(float) width / texture->width(),
(float) height / texture->height(),
texture->width() / (float) x,
@@ -220,7 +234,8 @@ GrFragmentProcessor* GrMagnifierEffect::TestCreate(SkRandom* random,
bool GrMagnifierEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
const GrMagnifierEffect& s = sBase.cast<GrMagnifierEffect>();
- return (this->fXOffset == s.fXOffset &&
+ return (this->fBounds == s.fBounds &&
+ this->fXOffset == s.fXOffset &&
this->fYOffset == s.fYOffset &&
this->fXInvZoom == s.fXInvZoom &&
this->fYInvZoom == s.fYInvZoom &&
@@ -258,18 +273,27 @@ SkMagnifierImageFilter::SkMagnifierImageFilter(const SkRect& srcRect, SkScalar i
#if SK_SUPPORT_GPU
bool SkMagnifierImageFilter::asFragmentProcessor(GrFragmentProcessor** fp, GrTexture* texture,
- const SkMatrix&, const SkIRect&) const {
+ const SkMatrix&, const SkIRect&bounds) const {
if (fp) {
- SkScalar yOffset = (texture->origin() == kTopLeft_GrSurfaceOrigin) ? fSrcRect.y() :
- (texture->height() - (fSrcRect.y() + fSrcRect.height()));
+ SkScalar yOffset = texture->origin() == kTopLeft_GrSurfaceOrigin ? fSrcRect.y() :
+ texture->height() - fSrcRect.height() * texture->height() / bounds.height()
+ - fSrcRect.y();
+ int boundsY = (texture->origin() == kTopLeft_GrSurfaceOrigin) ? bounds.y() :
+ (texture->height() - bounds.height());
+ SkRect effectBounds = SkRect::MakeXYWH(
+ SkIntToScalar(bounds.x()) / texture->width(),
+ SkIntToScalar(boundsY) / texture->height(),
+ SkIntToScalar(texture->width()) / bounds.width(),
+ SkIntToScalar(texture->height()) / bounds.height());
SkScalar invInset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1;
*fp = GrMagnifierEffect::Create(texture,
+ effectBounds,
fSrcRect.x() / texture->width(),
yOffset / texture->height(),
- fSrcRect.width() / texture->width(),
- fSrcRect.height() / texture->height(),
- texture->width() * invInset,
- texture->height() * invInset);
+ fSrcRect.width() / bounds.width(),
+ fSrcRect.height() / bounds.height(),
+ bounds.width() * invInset,
+ bounds.height() * invInset);
}
return true;
}
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 38a22e69f5..021cfba106 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -121,10 +121,15 @@ public:
///////////////////////////////////////////////////////////////////////////////
SkGpuDevice* SkGpuDevice::Create(GrRenderTarget* rt, const SkSurfaceProps* props, unsigned flags) {
+ return SkGpuDevice::Create(rt, rt->width(), rt->height(), props, flags);
+}
+
+SkGpuDevice* SkGpuDevice::Create(GrRenderTarget* rt, int width, int height,
+ const SkSurfaceProps* props, unsigned flags) {
if (!rt || rt->wasDestroyed()) {
return NULL;
}
- return SkNEW_ARGS(SkGpuDevice, (rt, props, flags));
+ return SkNEW_ARGS(SkGpuDevice, (rt, width, height, props, flags));
}
static SkDeviceProperties surfaceprops_to_deviceprops(const SkSurfaceProps* props) {
@@ -143,7 +148,8 @@ static SkSurfaceProps copy_or_default_props(const SkSurfaceProps* props) {
}
}
-SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, const SkSurfaceProps* props, unsigned flags)
+SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, int width, int height,
+ const SkSurfaceProps* props, unsigned flags)
: INHERITED(surfaceprops_to_deviceprops(props))
, fSurfaceProps(copy_or_default_props(props))
{
@@ -154,7 +160,7 @@ SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, const SkSurfaceProps* props, unsign
fRenderTarget = SkRef(rt);
- SkImageInfo info = rt->surfacePriv().info();
+ SkImageInfo info = rt->surfacePriv().info().makeWH(width, height);
SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, rt));
fLegacyBitmap.setInfo(info);
fLegacyBitmap.setPixelRef(pr)->unref();
@@ -211,7 +217,7 @@ SkGpuDevice* SkGpuDevice::Create(GrContext* context, SkSurface::Budgeted budgete
return NULL;
}
- return SkNEW_ARGS(SkGpuDevice, (rt, props, flags));
+ return SkNEW_ARGS(SkGpuDevice, (rt, info.width(), info.height(), props, flags));
}
SkGpuDevice::~SkGpuDevice() {
@@ -736,9 +742,9 @@ GrTexture* create_mask_GPU(GrContext* context,
return mask;
}
-SkBitmap wrap_texture(GrTexture* texture) {
+SkBitmap wrap_texture(GrTexture* texture, int width, int height) {
SkBitmap result;
- result.setInfo(texture->surfacePriv().info());
+ result.setInfo(SkImageInfo::MakeN32Premul(width, height));
result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (result.info(), texture)))->unref();
return result;
}
@@ -1474,6 +1480,7 @@ void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
}
bool SkGpuDevice::filterTexture(GrContext* context, GrTexture* texture,
+ int width, int height,
const SkImageFilter* filter,
const SkImageFilter::Context& ctx,
SkBitmap* result, SkIPoint* offset) {
@@ -1484,7 +1491,8 @@ bool SkGpuDevice::filterTexture(GrContext* context, GrTexture* texture,
SkDeviceImageFilterProxy proxy(this, SkSurfaceProps(0, getLeakyProperties().pixelGeometry()));
if (filter->canFilterImageGPU()) {
- return filter->filterImageGPU(&proxy, wrap_texture(texture), ctx, result, offset);
+ return filter->filterImageGPU(&proxy, wrap_texture(texture, width, height),
+ ctx, result, offset);
} else {
return false;
}
@@ -1523,7 +1531,7 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
// This cache is transient, and is freed (along with all its contained
// textures) when it goes out of scope.
SkImageFilter::Context ctx(matrix, clipBounds, cache);
- if (this->filterTexture(fContext, texture, filter, ctx, &filteredBitmap,
+ if (this->filterTexture(fContext, texture, w, h, filter, ctx, &filteredBitmap,
&offset)) {
texture = (GrTexture*) filteredBitmap.getTexture();
w = filteredBitmap.width();
@@ -1637,8 +1645,8 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
// textures) when it goes out of scope.
SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache());
SkImageFilter::Context ctx(matrix, clipBounds, cache);
- if (this->filterTexture(fContext, devTex, filter, ctx, &filteredBitmap,
- &offset)) {
+ if (this->filterTexture(fContext, devTex, device->width(), device->height(),
+ filter, ctx, &filteredBitmap, &offset)) {
devTex = filteredBitmap.getTexture();
w = filteredBitmap.width();
h = filteredBitmap.height();
@@ -1691,7 +1699,8 @@ bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
// must be pushed upstack.
AutoBitmapTexture abt(fContext, src, NULL, &texture);
- return this->filterTexture(fContext, texture, filter, ctx, result, offset);
+ return this->filterTexture(fContext, texture, src.width(), src.height(),
+ filter, ctx, result, offset);
}
///////////////////////////////////////////////////////////////////////////////
@@ -1901,7 +1910,8 @@ SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint
if (texture) {
SkSurfaceProps props(fSurfaceProps.flags(), cinfo.fPixelGeometry);
- return SkGpuDevice::Create(texture->asRenderTarget(), &props, flags);
+ return SkGpuDevice::Create(
+ texture->asRenderTarget(), cinfo.fInfo.width(), cinfo.fInfo.height(), &props, flags);
} else {
SkErrorInternals::SetError( kInternalError_SkError,
"---- failed to create compatible device texture [%d %d]\n",
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index ad0c2d63f0..999a698ded 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -41,6 +41,13 @@ public:
static SkGpuDevice* Create(GrRenderTarget* target, const SkSurfaceProps*, unsigned flags = 0);
/**
+ * Creates an SkGpuDevice from a GrRenderTarget whose texture width/height is
+ * different than its actual width/height (e.g., approx-match scratch texture).
+ */
+ static SkGpuDevice* Create(GrRenderTarget* target, int width, int height,
+ const SkSurfaceProps*, unsigned flags = 0);
+
+ /**
* New device that will create an offscreen renderTarget based on the ImageInfo and
* sampleCount. The Budgeted param controls whether the device's backing store counts against
* the resource cache budget. On failure, returns NULL.
@@ -67,7 +74,7 @@ public:
GrRenderTarget* accessRenderTarget() override;
SkImageInfo imageInfo() const override {
- return fRenderTarget ? fRenderTarget->surfacePriv().info() : SkImageInfo::MakeUnknown();
+ return fLegacyBitmap.info();
}
const SkSurfaceProps& surfaceProps() const { return fSurfaceProps; }
@@ -121,7 +128,7 @@ public:
const SkImageFilter::Context&,
SkBitmap*, SkIPoint*) override;
- bool filterTexture(GrContext*, GrTexture*, const SkImageFilter*,
+ bool filterTexture(GrContext*, GrTexture*, int width, int height, const SkImageFilter*,
const SkImageFilter::Context&,
SkBitmap* result, SkIPoint* offset);
@@ -147,7 +154,7 @@ private:
SkBitmap fLegacyBitmap;
bool fNeedClear;
- SkGpuDevice(GrRenderTarget*, const SkSurfaceProps*, unsigned flags);
+ SkGpuDevice(GrRenderTarget*, int width, int height, const SkSurfaceProps*, unsigned flags);
SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;