diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkCanvas.cpp | 8 | ||||
-rw-r--r-- | src/effects/SkLightingImageFilter.cpp | 444 | ||||
-rw-r--r-- | src/effects/SkMagnifierImageFilter.cpp | 51 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 53 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.h | 13 | ||||
-rw-r--r-- | src/gpu/effects/GrMatrixConvolutionEffect.cpp | 3 | ||||
-rw-r--r-- | src/gpu/effects/GrTextureDomain.h | 13 |
7 files changed, 458 insertions, 127 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/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp index 72dcf64c58..972d9ac68b 100644 --- a/src/effects/SkLightingImageFilter.cpp +++ b/src/effects/SkLightingImageFilter.cpp @@ -277,7 +277,136 @@ void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) { buffer.writeScalar(point.fZ); }; -class SkDiffuseLightingImageFilter : public SkLightingImageFilter { +enum BoundaryMode { + kTopLeft_BoundaryMode, + kTop_BoundaryMode, + kTopRight_BoundaryMode, + kLeft_BoundaryMode, + kInterior_BoundaryMode, + kRight_BoundaryMode, + kBottomLeft_BoundaryMode, + kBottom_BoundaryMode, + kBottomRight_BoundaryMode, + + kBoundaryModeCount, +}; + +class SkLightingImageFilterInternal : public SkLightingImageFilter { +protected: + SkLightingImageFilterInternal(SkLight* light, + SkScalar surfaceScale, + SkImageFilter* input, + const CropRect* cropRect) + : INHERITED(light, surfaceScale, input, cropRect) {} + +#if SK_SUPPORT_GPU + bool canFilterImageGPU() const override { return true; } + bool filterImageGPU(Proxy*, const SkBitmap& src, const Context&, + SkBitmap* result, SkIPoint* offset) const override; + virtual GrFragmentProcessor* getFragmentProcessor(GrTexture*, + const SkMatrix&, + const SkIRect& bounds, + BoundaryMode boundaryMode) const = 0; +#endif +private: +#if SK_SUPPORT_GPU + void drawRect(GrContext* context, + GrTexture* src, + GrTexture* dst, + const SkMatrix& matrix, + const GrClip& clip, + const SkRect& dstRect, + BoundaryMode boundaryMode, + const SkIRect& bounds) const; +#endif + typedef SkLightingImageFilter INHERITED; +}; + +#if SK_SUPPORT_GPU +void SkLightingImageFilterInternal::drawRect(GrContext* context, + GrTexture* src, + GrTexture* dst, + const SkMatrix& matrix, + const GrClip& clip, + const SkRect& dstRect, + BoundaryMode boundaryMode, + const SkIRect& bounds) const { + SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y())); + GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode); + GrPaint paint; + paint.addColorProcessor(fp)->unref(); + context->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(), + dstRect, srcRect); +} + +bool SkLightingImageFilterInternal::filterImageGPU(Proxy* proxy, + const SkBitmap& src, + const Context& ctx, + SkBitmap* result, + SkIPoint* offset) const { + SkBitmap input = src; + SkIPoint srcOffset = SkIPoint::Make(0, 0); + if (this->getInput(0) && + !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) { + return false; + } + SkIRect bounds; + if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) { + return false; + } + SkRect dstRect = SkRect::MakeWH(SkIntToScalar(bounds.width()), + SkIntToScalar(bounds.height())); + GrTexture* srcTexture = input.getTexture(); + GrContext* context = srcTexture->getContext(); + + GrSurfaceDesc desc; + desc.fFlags = kRenderTarget_GrSurfaceFlag, + desc.fWidth = bounds.width(); + desc.fHeight = bounds.height(); + desc.fConfig = kRGBA_8888_GrPixelConfig; + + SkAutoTUnref<GrTexture> dst( + context->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch)); + if (!dst) { + return false; + } + + // setup new clip + GrClip clip(dstRect); + + offset->fX = bounds.left(); + offset->fY = bounds.top(); + SkMatrix matrix(ctx.ctm()); + matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); + bounds.offset(-srcOffset); + SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1); + SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1); + SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1); + SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2); + SkRect interior = dstRect.makeInset(1, 1); + SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2); + SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1); + SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1); + SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1); + this->drawRect(context, srcTexture, dst, matrix, clip, topLeft, kTopLeft_BoundaryMode, bounds); + this->drawRect(context, srcTexture, dst, matrix, clip, top, kTop_BoundaryMode, bounds); + this->drawRect(context, srcTexture, dst, matrix, clip, topRight, kTopRight_BoundaryMode, + bounds); + this->drawRect(context, srcTexture, dst, matrix, clip, left, kLeft_BoundaryMode, bounds); + this->drawRect(context, srcTexture, dst, matrix, clip, interior, kInterior_BoundaryMode, + bounds); + this->drawRect(context, srcTexture, dst, matrix, clip, right, kRight_BoundaryMode, bounds); + this->drawRect(context, srcTexture, dst, matrix, clip, bottomLeft, kBottomLeft_BoundaryMode, + bounds); + this->drawRect(context, srcTexture, dst, matrix, clip, bottom, kBottom_BoundaryMode, bounds); + this->drawRect(context, srcTexture, dst, matrix, clip, bottomRight, kBottomRight_BoundaryMode, + bounds); + WrapTexture(dst, bounds.width(), bounds.height(), result); + return true; +} +#endif + +class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal { public: static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter*, const CropRect*); @@ -290,20 +419,20 @@ protected: SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect); void flatten(SkWriteBuffer& buffer) const override; - virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, - SkBitmap* result, SkIPoint* offset) const override; + bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, + SkBitmap* result, SkIPoint* offset) const override; #if SK_SUPPORT_GPU - virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&, - const SkIRect& bounds) const override; + GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, + const SkIRect& bounds, BoundaryMode) const override; #endif private: friend class SkLightingImageFilter; - typedef SkLightingImageFilter INHERITED; + typedef SkLightingImageFilterInternal INHERITED; SkScalar fKD; }; -class SkSpecularLightingImageFilter : public SkLightingImageFilter { +class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal { public: static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*); @@ -318,30 +447,32 @@ protected: SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect*); void flatten(SkWriteBuffer& buffer) const override; - virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, - SkBitmap* result, SkIPoint* offset) const override; + bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, + SkBitmap* result, SkIPoint* offset) const override; #if SK_SUPPORT_GPU - virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&, - const SkIRect& bounds) const override; + GrFragmentProcessor* getFragmentProcessor(GrTexture*, const SkMatrix&, + const SkIRect& bounds, BoundaryMode) const override; #endif private: SkScalar fKS; SkScalar fShininess; friend class SkLightingImageFilter; - typedef SkLightingImageFilter INHERITED; + typedef SkLightingImageFilterInternal INHERITED; }; #if SK_SUPPORT_GPU class GrLightingEffect : public GrSingleTextureEffect { public: - GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix); + GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, + const SkMatrix& matrix, BoundaryMode boundaryMode); virtual ~GrLightingEffect(); const SkLight* light() const { return fLight; } SkScalar surfaceScale() const { return fSurfaceScale; } const SkMatrix& filterMatrix() const { return fFilterMatrix; } + BoundaryMode boundaryMode() const { return fBoundaryMode; } protected: bool onIsEqual(const GrFragmentProcessor&) const override; @@ -356,6 +487,7 @@ private: const SkLight* fLight; SkScalar fSurfaceScale; SkMatrix fFilterMatrix; + BoundaryMode fBoundaryMode; }; class GrDiffuseLightingEffect : public GrLightingEffect { @@ -364,12 +496,14 @@ public: const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix, - SkScalar kd) { + SkScalar kd, + BoundaryMode boundaryMode) { return SkNEW_ARGS(GrDiffuseLightingEffect, (texture, light, surfaceScale, matrix, - kd)); + kd, + boundaryMode)); } const char* name() const override { return "DiffuseLighting"; } @@ -387,7 +521,8 @@ private: const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix, - SkScalar kd); + SkScalar kd, + BoundaryMode boundaryMode); GR_DECLARE_FRAGMENT_PROCESSOR_TEST; typedef GrLightingEffect INHERITED; @@ -401,13 +536,15 @@ public: SkScalar surfaceScale, const SkMatrix& matrix, SkScalar ks, - SkScalar shininess) { + SkScalar shininess, + BoundaryMode boundaryMode) { return SkNEW_ARGS(GrSpecularLightingEffect, (texture, light, surfaceScale, matrix, ks, - shininess)); + shininess, + boundaryMode)); } const char* name() const override { return "SpecularLighting"; } @@ -427,7 +564,8 @@ private: SkScalar surfaceScale, const SkMatrix& matrix, SkScalar ks, - SkScalar shininess); + SkScalar shininess, + BoundaryMode boundaryMode); GR_DECLARE_FRAGMENT_PROCESSOR_TEST; typedef GrLightingEffect INHERITED; @@ -481,8 +619,7 @@ private: class GrGLDistantLight : public GrGLLight { public: virtual ~GrGLDistantLight() {} - virtual void setData(const GrGLProgramDataManager&, - const SkLight* light) const override; + void setData(const GrGLProgramDataManager&, const SkLight* light) const override; void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override; private: @@ -495,8 +632,7 @@ private: class GrGLPointLight : public GrGLLight { public: virtual ~GrGLPointLight() {} - virtual void setData(const GrGLProgramDataManager&, - const SkLight* light) const override; + void setData(const GrGLProgramDataManager&, const SkLight* light) const override; void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override; private: @@ -509,8 +645,7 @@ private: class GrGLSpotLight : public GrGLLight { public: virtual ~GrGLSpotLight() {} - virtual void setData(const GrGLProgramDataManager&, - const SkLight* light) const override; + void setData(const GrGLProgramDataManager&, const SkLight* light) const override; void emitSurfaceToLight(GrGLFPBuilder*, const char* z) override; void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) override; @@ -695,7 +830,11 @@ private: class SkSpotLight : public SkLight { public: - SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color) + SkSpotLight(const SkPoint3& location, + const SkPoint3& target, + SkScalar specularExponent, + SkScalar cutoffAngle, + SkColor color) : INHERITED(color), fLocation(location), fTarget(target), @@ -723,7 +862,14 @@ public: SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY)); SkPoint3 s = target - location; s.normalize(); - return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color()); + return new SkSpotLight(location, + target, + fSpecularExponent, + fCosOuterConeAngle, + fCosInnerConeAngle, + fConeScale, + s, + color()); } SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const { @@ -777,7 +923,14 @@ public: SkScalarIsFinite(fConeScale)); } protected: - SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color) + SkSpotLight(const SkPoint3& location, + const SkPoint3& target, + SkScalar specularExponent, + SkScalar cosOuterConeAngle, + SkScalar cosInnerConeAngle, + SkScalar coneScale, + const SkPoint3& s, + const SkPoint3& color) : INHERITED(color), fLocation(location), fTarget(target), @@ -960,8 +1113,12 @@ SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar sur return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect)); } -SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect) - : SkLightingImageFilter(light, surfaceScale, input, cropRect), +SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, + SkScalar surfaceScale, + SkScalar kd, + SkImageFilter* input, + const CropRect* cropRect) + : INHERITED(light, surfaceScale, input, cropRect), fKD(kd) { } @@ -1020,13 +1177,28 @@ bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy, bounds.offset(-srcOffset); switch (transformedLight->type()) { case SkLight::kDistant_LightType: - lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds); + lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, + transformedLight, + src, + dst, + surfaceScale(), + bounds); break; case SkLight::kPoint_LightType: - lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds); + lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, + transformedLight, + src, + dst, + surfaceScale(), + bounds); break; case SkLight::kSpot_LightType: - lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds); + lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, + transformedLight, + src, + dst, + surfaceScale(), + bounds); break; } @@ -1042,15 +1214,14 @@ void SkDiffuseLightingImageFilter::toString(SkString* str) const { #endif #if SK_SUPPORT_GPU -bool SkDiffuseLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp, +GrFragmentProcessor* SkDiffuseLightingImageFilter::getFragmentProcessor( GrTexture* texture, const SkMatrix& matrix, - const SkIRect&) const { - if (fp) { - SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255)); - *fp = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd()); - } - return true; + const SkIRect&, + BoundaryMode boundaryMode +) const { + SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255)); + return GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd(), boundaryMode); } #endif @@ -1073,8 +1244,13 @@ SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar su (light, surfaceScale, ks, shininess, input, cropRect)); } -SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) - : SkLightingImageFilter(light, surfaceScale, input, cropRect), +SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, + SkScalar surfaceScale, + SkScalar ks, + SkScalar shininess, + SkImageFilter* input, + const CropRect* cropRect) + : INHERITED(light, surfaceScale, input, cropRect), fKS(ks), fShininess(shininess) { @@ -1136,13 +1312,28 @@ bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy, SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm())); switch (transformedLight->type()) { case SkLight::kDistant_LightType: - lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds); + lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, + transformedLight, + src, + dst, + surfaceScale(), + bounds); break; case SkLight::kPoint_LightType: - lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds); + lightBitmap<SpecularLightingType, SkPointLight>(lightingType, + transformedLight, + src, + dst, + surfaceScale(), + bounds); break; case SkLight::kSpot_LightType: - lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds); + lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, + transformedLight, + src, + dst, + surfaceScale(), + bounds); break; } return true; @@ -1157,15 +1348,14 @@ void SkSpecularLightingImageFilter::toString(SkString* str) const { #endif #if SK_SUPPORT_GPU -bool SkSpecularLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp, - GrTexture* texture, - const SkMatrix& matrix, - const SkIRect&) const { - if (fp) { - SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255)); - *fp = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess()); - } - return true; +GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor( + GrTexture* texture, + const SkMatrix& matrix, + const SkIRect&, + BoundaryMode boundaryMode) const { + SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255)); + return GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess(), + boundaryMode); } #endif @@ -1202,6 +1392,81 @@ SkLight* create_random_light(SkRandom* random) { } } +SkString emitNormalFunc(BoundaryMode mode, + const char* pointToNormalName, + const char* sobelFuncName) { + SkString result; + switch (mode) { + case kTopLeft_BoundaryMode: + result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n" + "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n" + "\t surfaceScale);\n", + pointToNormalName, sobelFuncName, gTwoThirds, + sobelFuncName, gTwoThirds); + break; + case kTop_BoundaryMode: + result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n" + "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n" + "\t surfaceScale);\n", + pointToNormalName, sobelFuncName, gOneThird, + sobelFuncName, gOneHalf); + break; + case kTopRight_BoundaryMode: + result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n" + "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n" + "\t surfaceScale);\n", + pointToNormalName, sobelFuncName, gTwoThirds, + sobelFuncName, gTwoThirds); + break; + case kLeft_BoundaryMode: + result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n" + "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n" + "\t surfaceScale);\n", + pointToNormalName, sobelFuncName, gOneHalf, + sobelFuncName, gOneThird); + break; + case kInterior_BoundaryMode: + result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n" + "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n" + "\t surfaceScale);\n", + pointToNormalName, sobelFuncName, gOneQuarter, + sobelFuncName, gOneQuarter); + break; + case kRight_BoundaryMode: + result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n" + "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n" + "\t surfaceScale);\n", + pointToNormalName, sobelFuncName, gOneHalf, + sobelFuncName, gOneThird); + break; + case kBottomLeft_BoundaryMode: + result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n" + "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n" + "\t surfaceScale);\n", + pointToNormalName, sobelFuncName, gTwoThirds, + sobelFuncName, gTwoThirds); + break; + case kBottom_BoundaryMode: + result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n" + "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n" + "\t surfaceScale);\n", + pointToNormalName, sobelFuncName, gOneThird, + sobelFuncName, gOneHalf); + break; + case kBottomRight_BoundaryMode: + result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n" + "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n" + "\t surfaceScale);\n", + pointToNormalName, sobelFuncName, gTwoThirds, + sobelFuncName, gTwoThirds); + break; + default: + SkASSERT(false); + break; + } + return result; +} + } class GrGLLightingEffect : public GrGLFragmentProcessor { @@ -1209,12 +1474,12 @@ public: GrGLLightingEffect(const GrProcessor&); virtual ~GrGLLightingEffect(); - virtual void emitCode(GrGLFPBuilder*, - const GrFragmentProcessor&, - const char* outputColor, - const char* inputColor, - const TransformedCoordsArray&, - const TextureSamplerArray&) override; + void emitCode(GrGLFPBuilder*, + const GrFragmentProcessor&, + const char* outputColor, + const char* inputColor, + const TransformedCoordsArray&, + const TextureSamplerArray&) override; static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b); @@ -1232,6 +1497,7 @@ private: UniformHandle fImageIncrementUni; UniformHandle fSurfaceScaleUni; GrGLLight* fLight; + BoundaryMode fBoundaryMode; }; /////////////////////////////////////////////////////////////////////////////// @@ -1268,11 +1534,13 @@ private: GrLightingEffect::GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, - const SkMatrix& matrix) + const SkMatrix& matrix, + BoundaryMode boundaryMode) : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture)) , fLight(light) , fSurfaceScale(surfaceScale) - , fFilterMatrix(matrix) { + , fFilterMatrix(matrix) + , fBoundaryMode(boundaryMode) { fLight->ref(); if (light->requiresFragmentPosition()) { this->setWillReadFragmentPosition(); @@ -1286,7 +1554,8 @@ GrLightingEffect::~GrLightingEffect() { bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const { const GrLightingEffect& s = sBase.cast<GrLightingEffect>(); return fLight->isEqual(*s.fLight) && - fSurfaceScale == s.fSurfaceScale; + fSurfaceScale == s.fSurfaceScale && + fBoundaryMode == s.fBoundaryMode; } /////////////////////////////////////////////////////////////////////////////// @@ -1295,8 +1564,9 @@ GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix, - SkScalar kd) - : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) { + SkScalar kd, + BoundaryMode boundaryMode) + : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKD(kd) { this->initClassID<GrDiffuseLightingEffect>(); } @@ -1328,8 +1598,9 @@ GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(SkRandom* random, for (int i = 0; i < 9; i++) { matrix[i] = random->nextUScalar1(); } + BoundaryMode mode = static_cast<BoundaryMode>(random->nextU() % kBoundaryModeCount); return GrDiffuseLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx], - light, surfaceScale, matrix, kd); + light, surfaceScale, matrix, kd, mode); } @@ -1338,6 +1609,7 @@ GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(SkRandom* random, GrGLLightingEffect::GrGLLightingEffect(const GrProcessor& fp) { const GrLightingEffect& m = fp.cast<GrLightingEffect>(); fLight = m.light()->createGLLight(); + fBoundaryMode = m.boundaryMode(); } GrGLLightingEffect::~GrGLLightingEffect() { @@ -1388,27 +1660,23 @@ void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder, "pointToNormal", SK_ARRAY_COUNT(gPointToNormalArgs), gPointToNormalArgs, - "\treturn normalize(vec3(-x * scale, y * scale, 1));\n", + "\treturn normalize(vec3(-x * scale, -y * scale, 1));\n", &pointToNormalName); static const GrGLShaderVar gInteriorNormalArgs[] = { GrGLShaderVar("m", kFloat_GrSLType, 9), GrGLShaderVar("surfaceScale", kFloat_GrSLType), }; - SkString interiorNormalBody; - interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n" - "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n" - "\t surfaceScale);\n", - pointToNormalName.c_str(), - sobelFuncName.c_str(), - sobelFuncName.c_str()); - SkString interiorNormalName; + SkString normalBody = emitNormalFunc(fBoundaryMode, + pointToNormalName.c_str(), + sobelFuncName.c_str()); + SkString normalName; fsBuilder->emitFunction(kVec3f_GrSLType, - "interiorNormal", + "normal", SK_ARRAY_COUNT(gInteriorNormalArgs), gInteriorNormalArgs, - interiorNormalBody.c_str(), - &interiorNormalName); + normalBody.c_str(), + &normalName); fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str()); fsBuilder->codeAppend("\t\tfloat m[9];\n"); @@ -1417,7 +1685,7 @@ void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder, const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni); int index = 0; - for (int dy = -1; dy <= 1; dy++) { + for (int dy = 1; dy >= -1; dy--) { for (int dx = -1; dx <= 1; dx++) { SkString texCoords; texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc); @@ -1432,7 +1700,7 @@ void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder, fLight->emitSurfaceToLight(builder, arg.c_str()); fsBuilder->codeAppend(";\n"); fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ", - outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale); + outputColor, lightFunc.c_str(), normalName.c_str(), surfScale); fLight->emitLightColor(builder, "surfaceToLight"); fsBuilder->codeAppend(");\n"); SkString modulate; @@ -1442,7 +1710,8 @@ void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder, void GrGLLightingEffect::GenKey(const GrProcessor& proc, const GrGLCaps& caps, GrProcessorKeyBuilder* b) { - b->add32(proc.cast<GrLightingEffect>().light()->type()); + const GrLightingEffect& lighting = proc.cast<GrLightingEffect>(); + b->add32(lighting.boundaryMode() << 2 | lighting.light()->type()); } void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman, @@ -1500,8 +1769,9 @@ GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture, SkScalar surfaceScale, const SkMatrix& matrix, SkScalar ks, - SkScalar shininess) - : INHERITED(texture, light, surfaceScale, matrix), + SkScalar shininess, + BoundaryMode boundaryMode) + : INHERITED(texture, light, surfaceScale, matrix, boundaryMode), fKS(ks), fShininess(shininess) { this->initClassID<GrSpecularLightingEffect>(); @@ -1537,8 +1807,9 @@ GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(SkRandom* random, for (int i = 0; i < 9; i++) { matrix[i] = random->nextUScalar1(); } + BoundaryMode mode = static_cast<BoundaryMode>(random->nextU() % kBoundaryModeCount); return GrSpecularLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx], - light, surfaceScale, matrix, ks, shininess); + light, surfaceScale, matrix, ks, shininess, mode); } /////////////////////////////////////////////////////////////////////////////// @@ -1554,7 +1825,10 @@ void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "KS", &ks); fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, - kFloat_GrSLType, kDefault_GrSLPrecision, "Shininess", &shininess); + kFloat_GrSLType, + kDefault_GrSLPrecision, + "Shininess", + &shininess); static const GrGLShaderVar gLightArgs[] = { GrGLShaderVar("normal", kVec3f_GrSLType), diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp index 622713d796..6d2ee01d52 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,15 +50,22 @@ public: GrGLFragmentProcessor* createGLInstance() const override; + const SkRect& bounds() const { return fBounds; } // Bounds of source image. + // Offset to apply to zoomed pixels, (srcRect position / texture size). float x_offset() const { return fXOffset; } float y_offset() const { return fYOffset; } + + // Scale to apply to zoomed pixels (srcRect size / bounds size). float x_inv_zoom() const { return fXInvZoom; } float y_inv_zoom() const { return fYInvZoom; } + + // 1/radius over which to transition from unzoomed to zoomed pixels (bounds size / inset). float x_inv_inset() const { return fXInvInset; } float y_inv_inset() const { return fYInvInset; } private: GrMagnifierEffect(GrTexture* texture, + const SkRect& bounds, float xOffset, float yOffset, float xInvZoom, @@ -64,6 +73,7 @@ private: float xInvInset, float yInvInset) : GrSingleTextureEffect(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture)) + , fBounds(bounds) , fXOffset(xOffset) , fYOffset(yOffset) , fXInvZoom(xInvZoom) @@ -79,6 +89,7 @@ private: GR_DECLARE_FRAGMENT_PROCESSOR_TEST; + SkRect fBounds; float fXOffset; float fYOffset; float fXInvZoom; @@ -109,6 +120,7 @@ private: UniformHandle fOffsetVar; UniformHandle fInvZoomVar; UniformHandle fInvInsetVar; + UniformHandle fBoundsVar; typedef GrGLFragmentProcessor INHERITED; }; @@ -134,6 +146,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 +158,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 +191,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 +224,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 +239,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 +278,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..a3f26149e8 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; } @@ -1097,11 +1103,14 @@ static bool needs_texture_domain(const SkBitmap& bitmap, const SkMatrix& contextMatrix, bool bicubic) { bool needsTextureDomain = false; + GrTexture* tex = bitmap.getTexture(); + int width = tex ? tex->width() : bitmap.width(); + int height = tex ? tex->height() : bitmap.height(); if (bicubic || params.filterMode() != GrTextureParams::kNone_FilterMode) { // Need texture domain if drawing a sub rect - needsTextureDomain = srcRect.width() < bitmap.width() || - srcRect.height() < bitmap.height(); + needsTextureDomain = srcRect.width() < width || + srcRect.height() < height; if (!bicubic && needsTextureDomain && contextMatrix.rectStaysRect()) { // sampling is axis-aligned SkRect transformedRect; @@ -1136,15 +1145,17 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw, dstSize.fWidth = w; dstSize.fHeight = h; srcRect.set(0, 0, w, h); - flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag); } else { SkASSERT(dstSizePtr); srcRect = *srcRectPtr; dstSize = *dstSizePtr; - if (srcRect.fLeft <= 0 && srcRect.fTop <= 0 && - srcRect.fRight >= bitmap.width() && srcRect.fBottom >= bitmap.height()) { - flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag); - } + } + GrTexture* tex = bitmap.getTexture(); + int width = tex ? tex->width() : bitmap.width(); + int height = tex ? tex->height() : bitmap.height(); + if (srcRect.fLeft <= 0 && srcRect.fTop <= 0 && + srcRect.fRight >= width && srcRect.fBottom >= height) { + flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag); } // If the render target is not msaa and draw is antialiased, we call @@ -1474,6 +1485,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 +1496,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 +1536,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 +1650,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 +1704,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 +1915,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 2db40fc438..8c3414b1db 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; diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/src/gpu/effects/GrMatrixConvolutionEffect.cpp index cd6d7c1f86..f6b99eff8f 100644 --- a/src/gpu/effects/GrMatrixConvolutionEffect.cpp +++ b/src/gpu/effects/GrMatrixConvolutionEffect.cpp @@ -90,6 +90,7 @@ void GrGLMatrixConvolutionEffect::emitCode(GrGLFPBuilder* builder, fDomain.sampleTexture(fsBuilder, domain, "c", coord, samplers[0]); if (!fConvolveAlpha) { fsBuilder->codeAppend("c.rgb /= c.a;"); + fsBuilder->codeAppend("c.rgb = clamp(c.rgb, 0, 1);"); } fsBuilder->codeAppend("sum += c * k;"); } @@ -152,7 +153,7 @@ GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrTexture* texture, fGain(SkScalarToFloat(gain)), fBias(SkScalarToFloat(bias) / 255.0f), fConvolveAlpha(convolveAlpha), - fDomain(GrTextureDomain::MakeTexelDomain(texture, bounds), tileMode) { + fDomain(GrTextureDomain::MakeTexelDomainForMode(texture, bounds, tileMode), tileMode) { this->initClassID<GrMatrixConvolutionEffect>(); for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) { fKernel[i] = SkScalarToFloat(kernel[i]); diff --git a/src/gpu/effects/GrTextureDomain.h b/src/gpu/effects/GrTextureDomain.h index 7efd9f2dee..0331260be9 100644 --- a/src/gpu/effects/GrTextureDomain.h +++ b/src/gpu/effects/GrTextureDomain.h @@ -69,6 +69,19 @@ public: return result; } + static const SkRect MakeTexelDomainForMode(const GrTexture* texture, const SkIRect& texelRect, Mode mode) { + // For Clamp mode, inset by half a texel. + SkScalar wInv = SK_Scalar1 / texture->width(); + SkScalar hInv = SK_Scalar1 / texture->height(); + SkScalar inset = mode == kClamp_Mode ? SK_ScalarHalf : 0; + return SkRect::MakeLTRB( + (texelRect.fLeft + inset) * wInv, + (texelRect.fTop + inset) * hInv, + (texelRect.fRight - inset) * wInv, + (texelRect.fBottom - inset) * hInv + ); + } + bool operator== (const GrTextureDomain& that) const { return fMode == that.fMode && (kIgnore_Mode == fMode || fDomain == that.fDomain); } |