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, SkLightingImageFilter, SkMatrixConvolutionImageFilter, SkMatrixImageFilter) whose GPU implementation depends on 0..1 texture coordinates. 3) Remove the exception for GPU-side image filters in SkCanvas::internalSaveLayer(). For the lighting filters, there were two bugs which were cancelling each other out: the sobel filter matrix was being computed upside down, but then we'd negate the resulting normal. This worked fine in the exact-match case, but in the approx-match case we'd sample garbage along the edge pixels. Also, we never implemented the edge pixels according to spec in the GPU case. It requires a different fragment shader for each edge of the nine-patch, which meant we couldn't use asFragmentProcessor(), and had to implement the drawing via a filterImageGPU() override. In order to avoid polluting the public API, I inserted a new base class, SkLightingImageFilterInternal above Sk[Diffuse|Specular]LightingImageFilter to handle the implementation. For the SkMatrixConvolutionImageFilter, it seems the GLSL clamp() function occasionally returns values outside the clamped range, resulting in access of garbage texels even in GL_NEAREST. The fix here is to clamp to a rect inset by half a texel. There was also a bug in the unpremultiply step when fConvolveAlpha is false. For SkMatrixImageFilter, the fix was to make the generic draw path be more careful about when to use texture domain. If the bitmap already has a texture, use texture domain if the srcRect is smaller than the entire texture (not the entire bitmap). 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 Committed: https://skia.googlesource.com/skia/+/b97dafefe63ea0a1bbce8e8b209f4920983fb8b9 Committed: https://skia.googlesource.com/skia/+/f5f8518fe0bbd2703e4ffc1b11ad7b4312ff7641 Review URL: https://codereview.chromium.org/1034733002
This commit is contained in:
parent
b41f05787e
commit
46112cf2a7
@ -7,9 +7,10 @@
|
||||
|
||||
#include "gm.h"
|
||||
#include "SkLightingImageFilter.h"
|
||||
#include "SkOffsetImageFilter.h"
|
||||
|
||||
#define WIDTH 330
|
||||
#define HEIGHT 440
|
||||
#define HEIGHT 660
|
||||
|
||||
namespace skiagm {
|
||||
|
||||
@ -86,28 +87,70 @@ protected:
|
||||
SkPaint paint;
|
||||
|
||||
SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 10, 60, 65));
|
||||
SkImageFilter::CropRect fullSizeCropRect(SkRect::MakeXYWH(0, 0, 100, 100));
|
||||
SkAutoTUnref<SkImageFilter> noopCropped(SkOffsetImageFilter::Create(0, 0, NULL, &cropRect));
|
||||
|
||||
int y = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
const SkImageFilter::CropRect* cr = (i == 0) ? NULL : &cropRect;
|
||||
paint.setImageFilter(SkLightingImageFilter::CreatePointLitDiffuse(pointLocation, white, surfaceScale, kd, NULL, cr))->unref();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
const SkImageFilter::CropRect* cr = (i == 1) ? &cropRect : (i == 2) ? &fullSizeCropRect : NULL;
|
||||
SkImageFilter* input = (i == 2) ? noopCropped.get() : NULL;
|
||||
paint.setImageFilter(SkLightingImageFilter::CreatePointLitDiffuse(pointLocation,
|
||||
white,
|
||||
surfaceScale,
|
||||
kd,
|
||||
input,
|
||||
cr))->unref();
|
||||
drawClippedBitmap(canvas, paint, 0, y);
|
||||
|
||||
paint.setImageFilter(SkLightingImageFilter::CreateDistantLitDiffuse(distantDirection, white, surfaceScale, kd, NULL, cr))->unref();
|
||||
paint.setImageFilter(SkLightingImageFilter::CreateDistantLitDiffuse(distantDirection,
|
||||
white,
|
||||
surfaceScale,
|
||||
kd,
|
||||
input,
|
||||
cr))->unref();
|
||||
drawClippedBitmap(canvas, paint, 110, y);
|
||||
|
||||
paint.setImageFilter(SkLightingImageFilter::CreateSpotLitDiffuse(spotLocation, spotTarget, spotExponent, cutoffAngle, white, surfaceScale, kd, NULL, cr))->unref();
|
||||
paint.setImageFilter(SkLightingImageFilter::CreateSpotLitDiffuse(spotLocation,
|
||||
spotTarget,
|
||||
spotExponent,
|
||||
cutoffAngle,
|
||||
white,
|
||||
surfaceScale,
|
||||
kd,
|
||||
input,
|
||||
cr))->unref();
|
||||
drawClippedBitmap(canvas, paint, 220, y);
|
||||
|
||||
y += 110;
|
||||
|
||||
paint.setImageFilter(SkLightingImageFilter::CreatePointLitSpecular(pointLocation, white, surfaceScale, ks, shininess, NULL, cr))->unref();
|
||||
paint.setImageFilter(SkLightingImageFilter::CreatePointLitSpecular(pointLocation,
|
||||
white,
|
||||
surfaceScale,
|
||||
ks,
|
||||
shininess,
|
||||
input,
|
||||
cr))->unref();
|
||||
drawClippedBitmap(canvas, paint, 0, y);
|
||||
|
||||
paint.setImageFilter(SkLightingImageFilter::CreateDistantLitSpecular(distantDirection, white, surfaceScale, ks, shininess, NULL, cr))->unref();
|
||||
paint.setImageFilter(SkLightingImageFilter::CreateDistantLitSpecular(distantDirection,
|
||||
white,
|
||||
surfaceScale,
|
||||
ks,
|
||||
shininess,
|
||||
input,
|
||||
cr))->unref();
|
||||
drawClippedBitmap(canvas, paint, 110, y);
|
||||
|
||||
paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(spotLocation, spotTarget, spotExponent, cutoffAngle, white, surfaceScale, ks, shininess, NULL, cr))->unref();
|
||||
paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(spotLocation,
|
||||
spotTarget,
|
||||
spotExponent,
|
||||
cutoffAngle,
|
||||
white,
|
||||
surfaceScale,
|
||||
ks,
|
||||
shininess,
|
||||
input,
|
||||
cr))->unref();
|
||||
drawClippedBitmap(canvas, paint, 220, y);
|
||||
|
||||
y += 110;
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -40,6 +40,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
|
||||
@ -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;
|
||||
|
||||
|
@ -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]);
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user