aboutsummaryrefslogtreecommitdiffhomepage
path: root/gm/lighting.cpp
diff options
context:
space:
mode:
authorGravatar senorblanco <senorblanco@chromium.org>2015-04-02 04:54:56 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-04-02 04:54:57 -0700
commitd0d37cace08f12abf8d316e6949e947551d418e6 (patch)
treef78c9aa1fb8d77822aebe681b7386c7f006aaba4 /gm/lighting.cpp
parent160ebb2bfa0794d72d31a786793b13413289863d (diff)
Implement approx-match support in image filter saveLayer() offscreen.
Currently, the GPU-side image filter implementation creates exact-match textures for the offscreen backing stores for saveLayer(). This is because several filters have GPU implementations which depend on the texture coordinates being 0..1. The fix is three-fold: 1) Store the actual requested size in the SkGpuDevice, so that when wrapping it in an SkBitmap for passing to filterImage(), we can give it the original size. 2) Fix the filters (SkMagnifierImageFilter, 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 Committed: https://skia.googlesource.com/skia/+/46112cf2a7c7307f1c9eebb5f881cbda15aa460c Review URL: https://codereview.chromium.org/1034733002
Diffstat (limited to 'gm/lighting.cpp')
-rw-r--r--gm/lighting.cpp61
1 files changed, 52 insertions, 9 deletions
diff --git a/gm/lighting.cpp b/gm/lighting.cpp
index 36c8ba0e45..0bfbb47a95 100644
--- a/gm/lighting.cpp
+++ b/gm/lighting.cpp
@@ -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;