• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkAlphaType.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkColorPriv.h"
12 #include "include/core/SkColorType.h"
13 #include "include/core/SkFlattenable.h"
14 #include "include/core/SkImageFilter.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkMatrix.h"
17 #include "include/core/SkPoint.h"
18 #include "include/core/SkPoint3.h"
19 #include "include/core/SkRect.h"
20 #include "include/core/SkRefCnt.h"
21 #include "include/core/SkSamplingOptions.h"
22 #include "include/core/SkScalar.h"
23 #include "include/core/SkString.h"
24 #include "include/core/SkTypes.h"
25 #include "include/effects/SkImageFilters.h"
26 #include "include/private/base/SkFloatingPoint.h"
27 #include "include/private/base/SkTPin.h"
28 #include "src/core/SkImageFilter_Base.h"
29 #include "src/core/SkReadBuffer.h"
30 #include "src/core/SkSpecialImage.h"
31 #include "src/core/SkWriteBuffer.h"
32 
33 #include <array>
34 #include <cstdint>
35 #include <memory>
36 #include <utility>
37 
38 #if defined(SK_GANESH)
39 #include "include/gpu/GpuTypes.h"
40 #include "include/gpu/GrRecordingContext.h"
41 #include "include/gpu/GrTypes.h"
42 #include "include/private/SkSLSampleUsage.h"
43 #include "include/private/gpu/ganesh/GrTypesPriv.h"
44 #include "src/core/SkSLTypeShared.h"
45 #include "src/gpu/KeyBuilder.h"
46 #include "src/gpu/SkBackingFit.h"
47 #include "src/gpu/ganesh/GrCaps.h"
48 #include "src/gpu/ganesh/GrFragmentProcessor.h"
49 #include "src/gpu/ganesh/GrImageInfo.h"
50 #include "src/gpu/ganesh/GrProcessorUnitTest.h"
51 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
52 #include "src/gpu/ganesh/GrSamplerState.h"
53 #include "src/gpu/ganesh/GrShaderVar.h"
54 #include "src/gpu/ganesh/GrSurfaceProxy.h"
55 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
56 #include "src/gpu/ganesh/SurfaceFillContext.h"
57 #include "src/gpu/ganesh/effects/GrTextureEffect.h"
58 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
59 #include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
60 #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
61 
62 struct GrShaderCaps;
63 
64 // For brevity
65 typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
66 #endif
67 
68 #if GR_TEST_UTILS
69 #include "src/base/SkRandom.h"
70 #endif
71 
72 const SkScalar gOneThird = SkIntToScalar(1) / 3;
73 const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
74 const SkScalar gOneHalf = 0.5f;
75 const SkScalar gOneQuarter = 0.25f;
76 
77 #if defined(SK_GANESH)
setUniformPoint3(const GrGLSLProgramDataManager & pdman,UniformHandle uni,const SkPoint3 & point)78 static void setUniformPoint3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
79                              const SkPoint3& point) {
80     static_assert(sizeof(SkPoint3) == 3 * sizeof(float));
81     pdman.set3fv(uni, 1, &point.fX);
82 }
83 
setUniformNormal3(const GrGLSLProgramDataManager & pdman,UniformHandle uni,const SkPoint3 & point)84 static void setUniformNormal3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
85                               const SkPoint3& point) {
86     setUniformPoint3(pdman, uni, point);
87 }
88 #endif
89 
90 // Shift matrix components to the left, as we advance pixels to the right.
shiftMatrixLeft(int m[9])91 static inline void shiftMatrixLeft(int m[9]) {
92     m[0] = m[1];
93     m[3] = m[4];
94     m[6] = m[7];
95     m[1] = m[2];
96     m[4] = m[5];
97     m[7] = m[8];
98 }
99 
fast_normalize(SkPoint3 * vector)100 static inline void fast_normalize(SkPoint3* vector) {
101     // add a tiny bit so we don't have to worry about divide-by-zero
102     SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero;
103 #if defined(_MSC_VER) && _MSC_VER >= 1920
104     // Visual Studio 2019 has some kind of code-generation bug in release builds involving the
105     // lighting math in this file. Using the portable rsqrt avoids the issue. This issue appears
106     // to be specific to the collection of (inline) functions in this file that call into this
107     // function, not with sk_float_rsqrt itself.
108     SkScalar scale = sk_float_rsqrt_portable(magSq);
109 #else
110     SkScalar scale = sk_float_rsqrt(magSq);
111 #endif
112     vector->fX *= scale;
113     vector->fY *= scale;
114     vector->fZ *= scale;
115 }
116 
read_point3(SkReadBuffer & buffer)117 static SkPoint3 read_point3(SkReadBuffer& buffer) {
118     SkPoint3 point;
119     point.fX = buffer.readScalar();
120     point.fY = buffer.readScalar();
121     point.fZ = buffer.readScalar();
122     buffer.validate(SkScalarIsFinite(point.fX) &&
123                     SkScalarIsFinite(point.fY) &&
124                     SkScalarIsFinite(point.fZ));
125     return point;
126 }
127 
write_point3(const SkPoint3 & point,SkWriteBuffer & buffer)128 static void write_point3(const SkPoint3& point, SkWriteBuffer& buffer) {
129     buffer.writeScalar(point.fX);
130     buffer.writeScalar(point.fY);
131     buffer.writeScalar(point.fZ);
132 }
133 
134 namespace {
135 class GpuLight;
136 class SkImageFilterLight : public SkRefCnt {
137 public:
138     enum LightType {
139         kDistant_LightType,
140         kPoint_LightType,
141         kSpot_LightType,
142 
143         kLast_LightType = kSpot_LightType
144     };
145     virtual LightType type() const = 0;
color() const146     const SkPoint3& color() const { return fColor; }
147     virtual std::unique_ptr<GpuLight> createGpuLight() const = 0;
isEqual(const SkImageFilterLight & other) const148     virtual bool isEqual(const SkImageFilterLight& other) const {
149         return fColor == other.fColor;
150     }
151     virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
152 
153     // Defined below SkLight's subclasses.
154     void flattenLight(SkWriteBuffer& buffer) const;
155     static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
156 
157     virtual SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const = 0;
158     virtual SkPoint3 lightColor(const SkPoint3& surfaceToLight) const = 0;
159 
160 protected:
SkImageFilterLight(SkColor color)161     SkImageFilterLight(SkColor color) {
162         fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
163                                 SkIntToScalar(SkColorGetG(color)),
164                                 SkIntToScalar(SkColorGetB(color)));
165     }
SkImageFilterLight(const SkPoint3 & color)166     SkImageFilterLight(const SkPoint3& color) : fColor(color) {}
167 
SkImageFilterLight(SkReadBuffer & buffer)168     SkImageFilterLight(SkReadBuffer& buffer) {
169         fColor = read_point3(buffer);
170     }
171 
172     virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
173 
174 
175 private:
176     using INHERITED = SkRefCnt;
177     SkPoint3 fColor;
178 };
179 
180 class BaseLightingType {
181 public:
BaseLightingType()182     BaseLightingType() {}
~BaseLightingType()183     virtual ~BaseLightingType() {}
184 
185     virtual SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
186                             const SkPoint3& lightColor) const= 0;
187 };
188 
189 class DiffuseLightingType : public BaseLightingType {
190 public:
DiffuseLightingType(SkScalar kd)191     DiffuseLightingType(SkScalar kd)
192         : fKD(kd) {}
light(const SkPoint3 & normal,const SkPoint3 & surfaceTolight,const SkPoint3 & lightColor) const193     SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
194                     const SkPoint3& lightColor) const override {
195         SkScalar colorScale = fKD * normal.dot(surfaceTolight);
196         SkPoint3 color = lightColor.makeScale(colorScale);
197         return SkPackARGB32(255,
198                             SkTPin(SkScalarRoundToInt(color.fX), 0, 255),
199                             SkTPin(SkScalarRoundToInt(color.fY), 0, 255),
200                             SkTPin(SkScalarRoundToInt(color.fZ), 0, 255));
201     }
202 private:
203     SkScalar fKD;
204 };
205 
max_component(const SkPoint3 & p)206 static SkScalar max_component(const SkPoint3& p) {
207     return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
208 }
209 
210 class SpecularLightingType : public BaseLightingType {
211 public:
SpecularLightingType(SkScalar ks,SkScalar shininess)212     SpecularLightingType(SkScalar ks, SkScalar shininess)
213         : fKS(ks), fShininess(shininess) {}
light(const SkPoint3 & normal,const SkPoint3 & surfaceTolight,const SkPoint3 & lightColor) const214     SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
215                     const SkPoint3& lightColor) const override {
216         SkPoint3 halfDir(surfaceTolight);
217         halfDir.fZ += SK_Scalar1;        // eye position is always (0, 0, 1)
218         fast_normalize(&halfDir);
219         SkScalar colorScale = fKS * SkScalarPow(normal.dot(halfDir), fShininess);
220         SkPoint3 color = lightColor.makeScale(colorScale);
221         return SkPackARGB32(SkTPin(SkScalarRoundToInt(max_component(color)), 0, 255),
222                             SkTPin(SkScalarRoundToInt(color.fX), 0, 255),
223                             SkTPin(SkScalarRoundToInt(color.fY), 0, 255),
224                             SkTPin(SkScalarRoundToInt(color.fZ), 0, 255));
225     }
226 private:
227     SkScalar fKS;
228     SkScalar fShininess;
229 };
230 }  // anonymous namespace
231 
sobel(int a,int b,int c,int d,int e,int f,SkScalar scale)232 static inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
233     return (-a + b - 2 * c + 2 * d -e + f) * scale;
234 }
235 
pointToNormal(SkScalar x,SkScalar y,SkScalar surfaceScale)236 static inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
237     SkPoint3 vector = SkPoint3::Make(-x * surfaceScale, -y * surfaceScale, 1);
238     fast_normalize(&vector);
239     return vector;
240 }
241 
topLeftNormal(int m[9],SkScalar surfaceScale)242 static inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
243     return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
244                          sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
245                          surfaceScale);
246 }
247 
topNormal(int m[9],SkScalar surfaceScale)248 static inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
249     return pointToNormal(sobel(   0,    0, m[3], m[5], m[6], m[8], gOneThird),
250                          sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
251                          surfaceScale);
252 }
253 
topRightNormal(int m[9],SkScalar surfaceScale)254 static inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
255     return pointToNormal(sobel(   0,    0, m[3], m[4], m[6], m[7], gTwoThirds),
256                          sobel(m[3], m[6], m[4], m[7],    0,    0, gTwoThirds),
257                          surfaceScale);
258 }
259 
leftNormal(int m[9],SkScalar surfaceScale)260 static inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
261     return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
262                          sobel(   0,    0, m[1], m[7], m[2], m[8], gOneThird),
263                          surfaceScale);
264 }
265 
266 
interiorNormal(int m[9],SkScalar surfaceScale)267 static inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
268     return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
269                          sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
270                          surfaceScale);
271 }
272 
rightNormal(int m[9],SkScalar surfaceScale)273 static inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
274     return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
275                          sobel(m[0], m[6], m[1], m[7],    0,    0, gOneThird),
276                          surfaceScale);
277 }
278 
bottomLeftNormal(int m[9],SkScalar surfaceScale)279 static inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
280     return pointToNormal(sobel(m[1], m[2], m[4], m[5],    0,    0, gTwoThirds),
281                          sobel(   0,    0, m[1], m[4], m[2], m[5], gTwoThirds),
282                          surfaceScale);
283 }
284 
bottomNormal(int m[9],SkScalar surfaceScale)285 static inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
286     return pointToNormal(sobel(m[0], m[2], m[3], m[5],    0,    0, gOneThird),
287                          sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
288                          surfaceScale);
289 }
290 
bottomRightNormal(int m[9],SkScalar surfaceScale)291 static inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
292     return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0,  0, gTwoThirds),
293                          sobel(m[0], m[3], m[1], m[4], 0,  0, gTwoThirds),
294                          surfaceScale);
295 }
296 
297 namespace {
298 class UncheckedPixelFetcher {
299 public:
Fetch(const SkBitmap & src,int x,int y,const SkIRect & bounds)300     static inline uint32_t Fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) {
301         return SkGetPackedA32(*src.getAddr32(x, y));
302     }
303 };
304 
305 // The DecalPixelFetcher is used when the destination crop rect exceeds the input bitmap bounds.
306 class DecalPixelFetcher {
307 public:
Fetch(const SkBitmap & src,int x,int y,const SkIRect & bounds)308     static inline uint32_t Fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) {
309         if (x < bounds.fLeft || x >= bounds.fRight || y < bounds.fTop || y >= bounds.fBottom) {
310             return 0;
311         } else {
312             return SkGetPackedA32(*src.getAddr32(x, y));
313         }
314     }
315 };
316 }  // anonymous namespace
317 
318 template <class PixelFetcher>
lightBitmap(const BaseLightingType & lightingType,const SkImageFilterLight * l,const SkBitmap & src,SkBitmap * dst,SkScalar surfaceScale,const SkIRect & bounds)319 static void lightBitmap(const BaseLightingType& lightingType,
320                  const SkImageFilterLight* l,
321                  const SkBitmap& src,
322                  SkBitmap* dst,
323                  SkScalar surfaceScale,
324                  const SkIRect& bounds) {
325     SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
326     int left = bounds.left(), right = bounds.right();
327     int bottom = bounds.bottom();
328     int y = bounds.top();
329     SkIRect srcBounds = src.bounds();
330     SkPMColor* dptr = dst->getAddr32(0, 0);
331     {
332         int x = left;
333         int m[9];
334         m[4] = PixelFetcher::Fetch(src, x,     y,     srcBounds);
335         m[5] = PixelFetcher::Fetch(src, x + 1, y,     srcBounds);
336         m[7] = PixelFetcher::Fetch(src, x,     y + 1, srcBounds);
337         m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
338         SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
339         *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
340                                      l->lightColor(surfaceToLight));
341         for (++x; x < right - 1; ++x)
342         {
343             shiftMatrixLeft(m);
344             m[5] = PixelFetcher::Fetch(src, x + 1, y,     srcBounds);
345             m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
346             surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
347             *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
348                                          l->lightColor(surfaceToLight));
349         }
350         shiftMatrixLeft(m);
351         surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
352         *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
353                                      l->lightColor(surfaceToLight));
354     }
355 
356     for (++y; y < bottom - 1; ++y) {
357         int x = left;
358         int m[9];
359         m[1] = PixelFetcher::Fetch(src, x,     y - 1, srcBounds);
360         m[2] = PixelFetcher::Fetch(src, x + 1, y - 1, srcBounds);
361         m[4] = PixelFetcher::Fetch(src, x,     y,     srcBounds);
362         m[5] = PixelFetcher::Fetch(src, x + 1, y,     srcBounds);
363         m[7] = PixelFetcher::Fetch(src, x,     y + 1, srcBounds);
364         m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
365         SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
366         *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
367                                      l->lightColor(surfaceToLight));
368         for (++x; x < right - 1; ++x) {
369             shiftMatrixLeft(m);
370             m[2] = PixelFetcher::Fetch(src, x + 1, y - 1, srcBounds);
371             m[5] = PixelFetcher::Fetch(src, x + 1, y,     srcBounds);
372             m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds);
373             surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
374             *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
375                                          l->lightColor(surfaceToLight));
376         }
377         shiftMatrixLeft(m);
378         surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
379         *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
380                                      l->lightColor(surfaceToLight));
381     }
382 
383     {
384         int x = left;
385         int m[9];
386         m[1] = PixelFetcher::Fetch(src, x,     bottom - 2, srcBounds);
387         m[2] = PixelFetcher::Fetch(src, x + 1, bottom - 2, srcBounds);
388         m[4] = PixelFetcher::Fetch(src, x,     bottom - 1, srcBounds);
389         m[5] = PixelFetcher::Fetch(src, x + 1, bottom - 1, srcBounds);
390         SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
391         *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
392                                      l->lightColor(surfaceToLight));
393         for (++x; x < right - 1; ++x)
394         {
395             shiftMatrixLeft(m);
396             m[2] = PixelFetcher::Fetch(src, x + 1, bottom - 2, srcBounds);
397             m[5] = PixelFetcher::Fetch(src, x + 1, bottom - 1, srcBounds);
398             surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
399             *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
400                                          l->lightColor(surfaceToLight));
401         }
402         shiftMatrixLeft(m);
403         surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
404         *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
405                                      l->lightColor(surfaceToLight));
406     }
407 }
408 
lightBitmap(const BaseLightingType & lightingType,const SkImageFilterLight * light,const SkBitmap & src,SkBitmap * dst,SkScalar surfaceScale,const SkIRect & bounds)409 static void lightBitmap(const BaseLightingType& lightingType,
410                  const SkImageFilterLight* light,
411                  const SkBitmap& src,
412                  SkBitmap* dst,
413                  SkScalar surfaceScale,
414                  const SkIRect& bounds) {
415     if (src.bounds().contains(bounds)) {
416         lightBitmap<UncheckedPixelFetcher>(
417             lightingType, light, src, dst, surfaceScale, bounds);
418     } else {
419         lightBitmap<DecalPixelFetcher>(
420             lightingType, light, src, dst, surfaceScale, bounds);
421     }
422 }
423 
424 namespace {
425 enum BoundaryMode {
426     kTopLeft_BoundaryMode,
427     kTop_BoundaryMode,
428     kTopRight_BoundaryMode,
429     kLeft_BoundaryMode,
430     kInterior_BoundaryMode,
431     kRight_BoundaryMode,
432     kBottomLeft_BoundaryMode,
433     kBottom_BoundaryMode,
434     kBottomRight_BoundaryMode,
435 
436     kBoundaryModeCount,
437 };
438 
439 class SkLightingImageFilterInternal : public SkImageFilter_Base {
440 protected:
SkLightingImageFilterInternal(sk_sp<SkImageFilterLight> light,SkScalar surfaceScale,sk_sp<SkImageFilter> input,const SkRect * cropRect)441     SkLightingImageFilterInternal(sk_sp<SkImageFilterLight> light,
442                                   SkScalar surfaceScale,
443                                   sk_sp<SkImageFilter> input,
444                                   const SkRect* cropRect)
445             : INHERITED(&input, 1, cropRect)
446             , fLight(std::move(light))
447             , fSurfaceScale(surfaceScale / 255) {}
448 
flatten(SkWriteBuffer & buffer) const449     void flatten(SkWriteBuffer& buffer) const override {
450         this->INHERITED::flatten(buffer);
451         fLight->flattenLight(buffer);
452         buffer.writeScalar(fSurfaceScale * 255);
453     }
454 
onAffectsTransparentBlack() const455     bool onAffectsTransparentBlack() const override { return true; }
456 
light() const457     const SkImageFilterLight* light() const { return fLight.get(); }
refLight() const458     inline sk_sp<const SkImageFilterLight> refLight() const { return fLight; }
surfaceScale() const459     SkScalar surfaceScale() const { return fSurfaceScale; }
460 
461 #if defined(SK_GANESH)
462     sk_sp<SkSpecialImage> filterImageGPU(const Context& ctx,
463                                          SkSpecialImage* input,
464                                          const SkIRect& bounds,
465                                          const SkMatrix& matrix) const;
466     virtual std::unique_ptr<GrFragmentProcessor> makeFragmentProcessor(GrSurfaceProxyView,
467                                                                        const SkIPoint& viewOffset,
468                                                                        const SkMatrix&,
469                                                                        const SkIRect* srcBounds,
470                                                                        BoundaryMode boundaryMode,
471                                                                        const GrCaps&) const = 0;
472 #endif
473 
474 private:
475 #if defined(SK_GANESH)
476     void drawRect(skgpu::v1::SurfaceFillContext*,
477                   GrSurfaceProxyView srcView,
478                   const SkIPoint& viewOffset,
479                   const SkMatrix& matrix,
480                   const SkIRect& dstRect,
481                   BoundaryMode boundaryMode,
482                   const SkIRect* srcBounds,
483                   const SkIRect& bounds) const;
484 #endif
485 
486     sk_sp<SkImageFilterLight> fLight;
487     SkScalar fSurfaceScale;
488 
489     using INHERITED = SkImageFilter_Base;
490 };
491 }  // anonymous namespace
492 
493 #if defined(SK_GANESH)
drawRect(skgpu::v1::SurfaceFillContext * sfc,GrSurfaceProxyView srcView,const SkIPoint & viewOffset,const SkMatrix & matrix,const SkIRect & dstRect,BoundaryMode boundaryMode,const SkIRect * srcBounds,const SkIRect & bounds) const494 void SkLightingImageFilterInternal::drawRect(skgpu::v1::SurfaceFillContext* sfc,
495                                              GrSurfaceProxyView srcView,
496                                              const SkIPoint& viewOffset,
497                                              const SkMatrix& matrix,
498                                              const SkIRect& dstRect,
499                                              BoundaryMode boundaryMode,
500                                              const SkIRect* srcBounds,
501                                              const SkIRect& bounds) const {
502     SkIRect srcRect = dstRect.makeOffset(bounds.topLeft());
503     auto fp = this->makeFragmentProcessor(std::move(srcView), viewOffset, matrix, srcBounds,
504                                           boundaryMode, *sfc->caps());
505     sfc->fillRectToRectWithFP(srcRect, dstRect, std::move(fp));
506 }
507 
filterImageGPU(const Context & ctx,SkSpecialImage * input,const SkIRect & offsetBounds,const SkMatrix & matrix) const508 sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU(
509                                                    const Context& ctx,
510                                                    SkSpecialImage* input,
511                                                    const SkIRect& offsetBounds,
512                                                    const SkMatrix& matrix) const {
513     SkASSERT(ctx.gpuBacked());
514 
515     auto rContext = ctx.getContext();
516 
517     GrSurfaceProxyView inputView = input->view(rContext);
518     SkASSERT(inputView.asTextureProxy());
519 
520     GrImageInfo info(ctx.grColorType(),
521                      kPremul_SkAlphaType,
522                      ctx.refColorSpace(),
523                      offsetBounds.size());
524     auto sfc = rContext->priv().makeSFC(info,
525                                         "LightingImageFilterInternal_FilterImageGPU",
526                                         SkBackingFit::kApprox,
527                                         1,
528                                         skgpu::Mipmapped::kNo,
529                                         inputView.proxy()->isProtected(),
530                                         kBottomLeft_GrSurfaceOrigin);
531     if (!sfc) {
532         return nullptr;
533     }
534 
535     SkIRect dstRect = SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height());
536 
537     const SkIRect inputBounds = SkIRect::MakeWH(input->width(), input->height());
538     SkIRect topLeft = SkIRect::MakeXYWH(0, 0, 1, 1);
539     SkIRect top = SkIRect::MakeXYWH(1, 0, dstRect.width() - 2, 1);
540     SkIRect topRight = SkIRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1);
541     SkIRect left = SkIRect::MakeXYWH(0, 1, 1, dstRect.height() - 2);
542     SkIRect interior = dstRect.makeInset(1, 1);
543     SkIRect right = SkIRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2);
544     SkIRect bottomLeft = SkIRect::MakeXYWH(0, dstRect.height() - 1, 1, 1);
545     SkIRect bottom = SkIRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1);
546     SkIRect bottomRight = SkIRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1);
547 
548     const SkIRect* pSrcBounds = inputBounds.contains(offsetBounds) ? nullptr : &inputBounds;
549     const SkIPoint inputViewOffset = input->subset().topLeft();
550 
551     this->drawRect(sfc.get(), inputView, inputViewOffset, matrix, topLeft,
552                    kTopLeft_BoundaryMode, pSrcBounds, offsetBounds);
553     this->drawRect(sfc.get(), inputView, inputViewOffset, matrix, top,
554                    kTop_BoundaryMode, pSrcBounds, offsetBounds);
555     this->drawRect(sfc.get(), inputView, inputViewOffset, matrix, topRight,
556                    kTopRight_BoundaryMode, pSrcBounds, offsetBounds);
557     this->drawRect(sfc.get(), inputView, inputViewOffset, matrix, left,
558                    kLeft_BoundaryMode, pSrcBounds, offsetBounds);
559     this->drawRect(sfc.get(), inputView, inputViewOffset, matrix, interior,
560                    kInterior_BoundaryMode, pSrcBounds, offsetBounds);
561     this->drawRect(sfc.get(), inputView, inputViewOffset, matrix, right,
562                    kRight_BoundaryMode, pSrcBounds, offsetBounds);
563     this->drawRect(sfc.get(), inputView, inputViewOffset, matrix, bottomLeft,
564                    kBottomLeft_BoundaryMode, pSrcBounds, offsetBounds);
565     this->drawRect(sfc.get(), inputView, inputViewOffset, matrix, bottom,
566                    kBottom_BoundaryMode, pSrcBounds, offsetBounds);
567     this->drawRect(sfc.get(), std::move(inputView), inputViewOffset, matrix, bottomRight,
568                    kBottomRight_BoundaryMode, pSrcBounds, offsetBounds);
569 
570     return SkSpecialImage::MakeDeferredFromGpu(
571             rContext,
572             SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height()),
573             kNeedNewImageUniqueID_SpecialImage,
574             sfc->readSurfaceView(),
575             sfc->colorInfo(),
576             ctx.surfaceProps());
577 }
578 #endif
579 
580 namespace {
581 class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal {
582 public:
583     static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilterLight> light,
584                                      SkScalar surfaceScale,
585                                      SkScalar kd,
586                                      sk_sp<SkImageFilter>,
587                                      const SkRect*);
588 
kd() const589     SkScalar kd() const { return fKD; }
590 
591 protected:
592     SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light, SkScalar surfaceScale,
593                                  SkScalar kd,
594                                  sk_sp<SkImageFilter> input, const SkRect* cropRect);
595     void flatten(SkWriteBuffer& buffer) const override;
596 
597     sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
598 
599 #if defined(SK_GANESH)
600     std::unique_ptr<GrFragmentProcessor> makeFragmentProcessor(GrSurfaceProxyView,
601                                                                const SkIPoint& viewOffset,
602                                                                const SkMatrix&,
603                                                                const SkIRect* bounds,
604                                                                BoundaryMode,
605                                                                const GrCaps&) const override;
606 #endif
607 
608 private:
609     SK_FLATTENABLE_HOOKS(SkDiffuseLightingImageFilter)
610     friend void ::SkRegisterLightingImageFilterFlattenables();
611     SkScalar fKD;
612 
613     using INHERITED = SkLightingImageFilterInternal;
614 };
615 
616 class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal {
617 public:
618     static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilterLight> light,
619                                      SkScalar surfaceScale,
620                                      SkScalar ks, SkScalar shininess,
621                                      sk_sp<SkImageFilter>, const SkRect*);
622 
ks() const623     SkScalar ks() const { return fKS; }
shininess() const624     SkScalar shininess() const { return fShininess; }
625 
626 protected:
627     SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light,
628                                   SkScalar surfaceScale, SkScalar ks,
629                                   SkScalar shininess,
630                                   sk_sp<SkImageFilter> input, const SkRect*);
631     void flatten(SkWriteBuffer& buffer) const override;
632 
633     sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
634 
635 #if defined(SK_GANESH)
636     std::unique_ptr<GrFragmentProcessor> makeFragmentProcessor(GrSurfaceProxyView,
637                                                                const SkIPoint& viewOffset,
638                                                                const SkMatrix&,
639                                                                const SkIRect* bounds,
640                                                                BoundaryMode,
641                                                                const GrCaps&) const override;
642 #endif
643 
644 private:
645     SK_FLATTENABLE_HOOKS(SkSpecularLightingImageFilter)
646     friend void ::SkRegisterLightingImageFilterFlattenables();
647 
648     SkScalar fKS;
649     SkScalar fShininess;
650 
651     using INHERITED = SkLightingImageFilterInternal;
652 };
653 
654 #if defined(SK_GANESH)
655 
656 class LightingEffect : public GrFragmentProcessor {
657 public:
light() const658     const SkImageFilterLight* light() const { return fLight.get(); }
surfaceScale() const659     SkScalar surfaceScale() const { return fSurfaceScale; }
filterMatrix() const660     const SkMatrix& filterMatrix() const { return fFilterMatrix; }
boundaryMode() const661     BoundaryMode boundaryMode() const { return fBoundaryMode; }
662 
663 protected:
664     class ImplBase;
665 
666     LightingEffect(ClassID classID,
667                    GrSurfaceProxyView,
668                    const SkIPoint& viewOffset,
669                    sk_sp<const SkImageFilterLight> light,
670                    SkScalar surfaceScale,
671                    const SkMatrix& matrix,
672                    BoundaryMode boundaryMode,
673                    const SkIRect* srcBounds,
674                    const GrCaps& caps);
675 
676     explicit LightingEffect(const LightingEffect& that);
677 
678     bool onIsEqual(const GrFragmentProcessor&) const override;
679 
680 private:
onAddToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b) const681     void onAddToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const override {
682         b->add32(fBoundaryMode << 2 | fLight->type());
683     }
684 
685     sk_sp<const SkImageFilterLight> fLight;
686     SkScalar fSurfaceScale;
687     SkMatrix fFilterMatrix;
688     BoundaryMode fBoundaryMode;
689 
690     using INHERITED = GrFragmentProcessor;
691 };
692 
693 class DiffuseLightingEffect : public LightingEffect {
694 public:
Make(GrSurfaceProxyView view,const SkIPoint & viewOffset,sk_sp<const SkImageFilterLight> light,SkScalar surfaceScale,const SkMatrix & matrix,SkScalar kd,BoundaryMode boundaryMode,const SkIRect * srcBounds,const GrCaps & caps)695     static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView view,
696                                                      const SkIPoint& viewOffset,
697                                                      sk_sp<const SkImageFilterLight> light,
698                                                      SkScalar surfaceScale,
699                                                      const SkMatrix& matrix,
700                                                      SkScalar kd,
701                                                      BoundaryMode boundaryMode,
702                                                      const SkIRect* srcBounds,
703                                                      const GrCaps& caps) {
704         return std::unique_ptr<GrFragmentProcessor>(new DiffuseLightingEffect(std::move(view),
705                                                                               viewOffset,
706                                                                               std::move(light),
707                                                                               surfaceScale,
708                                                                               matrix,
709                                                                               kd,
710                                                                               boundaryMode,
711                                                                               srcBounds,
712                                                                               caps));
713     }
714 
name() const715     const char* name() const override { return "DiffuseLighting"; }
716 
clone() const717     std::unique_ptr<GrFragmentProcessor> clone() const override {
718         return std::unique_ptr<GrFragmentProcessor>(new DiffuseLightingEffect(*this));
719     }
720 
721 private:
722     class Impl;
723 
724     std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override;
725 
726     bool onIsEqual(const GrFragmentProcessor&) const override;
727 
728     DiffuseLightingEffect(GrSurfaceProxyView view,
729                           const SkIPoint& viewOffset,
730                           sk_sp<const SkImageFilterLight> light,
731                           SkScalar surfaceScale,
732                           const SkMatrix& matrix,
733                           SkScalar kd,
734                           BoundaryMode boundaryMode,
735                           const SkIRect* srcBounds,
736                           const GrCaps& caps);
737 
738     explicit DiffuseLightingEffect(const DiffuseLightingEffect& that);
739 
740     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
741     SkScalar fKD;
742 
743     using INHERITED = LightingEffect;
744 };
745 
746 class SpecularLightingEffect : public LightingEffect {
747 public:
Make(GrSurfaceProxyView view,const SkIPoint & viewOffset,sk_sp<const SkImageFilterLight> light,SkScalar surfaceScale,const SkMatrix & matrix,SkScalar ks,SkScalar shininess,BoundaryMode boundaryMode,const SkIRect * srcBounds,const GrCaps & caps)748     static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView view,
749                                                      const SkIPoint& viewOffset,
750                                                      sk_sp<const SkImageFilterLight> light,
751                                                      SkScalar surfaceScale,
752                                                      const SkMatrix& matrix,
753                                                      SkScalar ks,
754                                                      SkScalar shininess,
755                                                      BoundaryMode boundaryMode,
756                                                      const SkIRect* srcBounds,
757                                                      const GrCaps& caps) {
758         return std::unique_ptr<GrFragmentProcessor>(new SpecularLightingEffect(std::move(view),
759                                                                                viewOffset,
760                                                                                std::move(light),
761                                                                                surfaceScale,
762                                                                                matrix,
763                                                                                ks,
764                                                                                shininess,
765                                                                                boundaryMode,
766                                                                                srcBounds,
767                                                                                caps));
768     }
769 
name() const770     const char* name() const override { return "SpecularLighting"; }
771 
clone() const772     std::unique_ptr<GrFragmentProcessor> clone() const override {
773         return std::unique_ptr<GrFragmentProcessor>(new SpecularLightingEffect(*this));
774     }
775 
776     std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override;
777 
778 private:
779     class Impl;
780 
781     bool onIsEqual(const GrFragmentProcessor&) const override;
782 
783     SpecularLightingEffect(GrSurfaceProxyView,
784                            const SkIPoint& viewOffset,
785                            sk_sp<const SkImageFilterLight> light,
786                            SkScalar surfaceScale,
787                            const SkMatrix& matrix,
788                            SkScalar ks,
789                            SkScalar shininess,
790                            BoundaryMode boundaryMode,
791                            const SkIRect* srcBounds,
792                            const GrCaps&);
793 
794     explicit SpecularLightingEffect(const SpecularLightingEffect&);
795 
796     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
797     SkScalar fKS;
798     SkScalar fShininess;
799 
800     using INHERITED = LightingEffect;
801 };
802 
803 ///////////////////////////////////////////////////////////////////////////////
804 
805 class GpuLight {
806 public:
807     virtual ~GpuLight() = default;
808 
809     /**
810      * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
811      * below. It adds a half3 uniform visible in the FS that represents the constant light color.
812      */
813     void emitLightColorUniform(const GrFragmentProcessor*, GrGLSLUniformHandler*);
814 
815     /**
816      * These two functions are called from GrGLLightingEffect's emitCode() function.
817      * emitSurfaceToLight places an expression in param out that is the vector from the surface to
818      * the light. The expression will be used in the FS. emitLightColor writes an expression into
819      * the FS that is the color of the light. Either function may add functions and/or uniforms to
820      * the FS. The default of emitLightColor appends the name of the constant light color uniform
821      * and so this function only needs to be overridden if the light color varies spatially.
822      */
823     virtual void emitSurfaceToLight(const GrFragmentProcessor*,
824                                     GrGLSLUniformHandler*,
825                                     GrGLSLFPFragmentBuilder*,
826                                     const char* z) = 0;
827     virtual void emitLightColor(const GrFragmentProcessor*,
828                                 GrGLSLUniformHandler*,
829                                 GrGLSLFPFragmentBuilder*,
830                                 const char *surfaceToLight);
831 
832     // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
833     // INHERITED::setData().
834     virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const;
835 
836 protected:
837     /**
838      * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
839      * function.
840      */
lightColorUni() const841     UniformHandle lightColorUni() const { return fColorUni; }
842 
843 private:
844     UniformHandle fColorUni;
845 
846     using INHERITED = SkRefCnt;
847 };
848 
849 ///////////////////////////////////////////////////////////////////////////////
850 
851 class GpuDistantLight : public GpuLight {
852 public:
853     void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
854     void emitSurfaceToLight(const GrFragmentProcessor*, GrGLSLUniformHandler*,
855                             GrGLSLFPFragmentBuilder*, const char* z) override;
856 
857 private:
858     using INHERITED = GpuLight;
859     UniformHandle fDirectionUni;
860 };
861 
862 ///////////////////////////////////////////////////////////////////////////////
863 
864 class GpuPointLight : public GpuLight {
865 public:
866     void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
867     void emitSurfaceToLight(const GrFragmentProcessor*, GrGLSLUniformHandler*,
868                             GrGLSLFPFragmentBuilder*, const char* z) override;
869 
870 private:
871     using INHERITED = GpuLight;
872     UniformHandle fLocationUni;
873 };
874 
875 ///////////////////////////////////////////////////////////////////////////////
876 
877 class GpuSpotLight : public GpuLight {
878 public:
879     void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override;
880     void emitSurfaceToLight(const GrFragmentProcessor*, GrGLSLUniformHandler*,
881                             GrGLSLFPFragmentBuilder*, const char* z) override;
882     void emitLightColor(const GrFragmentProcessor*,
883                         GrGLSLUniformHandler*,
884                         GrGLSLFPFragmentBuilder*,
885                         const char *surfaceToLight) override;
886 
887 private:
888     using INHERITED = GpuLight;
889 
890     SkString        fLightColorFunc;
891     UniformHandle   fLocationUni;
892     UniformHandle   fExponentUni;
893     UniformHandle   fCosOuterConeAngleUni;
894     UniformHandle   fCosInnerConeAngleUni;
895     UniformHandle   fConeScaleUni;
896     UniformHandle   fSUni;
897 };
898 
899 #else
900 
901 class GpuLight {};
902 
903 #endif
904 
905 ///////////////////////////////////////////////////////////////////////////////
906 
907 class SkDistantLight : public SkImageFilterLight {
908 public:
SkDistantLight(const SkPoint3 & direction,SkColor color)909     SkDistantLight(const SkPoint3& direction, SkColor color)
910       : INHERITED(color), fDirection(direction) {
911     }
912 
surfaceToLight(int x,int y,int z,SkScalar surfaceScale) const913     SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const override {
914         return fDirection;
915     }
lightColor(const SkPoint3 &) const916     SkPoint3 lightColor(const SkPoint3&) const override { return this->color(); }
type() const917     LightType type() const override { return kDistant_LightType; }
direction() const918     const SkPoint3& direction() const { return fDirection; }
createGpuLight() const919     std::unique_ptr<GpuLight> createGpuLight() const override {
920 #if defined(SK_GANESH)
921         return std::make_unique<GpuDistantLight>();
922 #else
923         SkDEBUGFAIL("Should not call in GPU-less build");
924         return nullptr;
925 #endif
926     }
927 
isEqual(const SkImageFilterLight & other) const928     bool isEqual(const SkImageFilterLight& other) const override {
929         if (other.type() != kDistant_LightType) {
930             return false;
931         }
932 
933         const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
934         return INHERITED::isEqual(other) &&
935                fDirection == o.fDirection;
936     }
937 
SkDistantLight(SkReadBuffer & buffer)938     SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
939         fDirection = read_point3(buffer);
940     }
941 
942 protected:
SkDistantLight(const SkPoint3 & direction,const SkPoint3 & color)943     SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
944       : INHERITED(color), fDirection(direction) {
945     }
transform(const SkMatrix & matrix) const946     SkImageFilterLight* transform(const SkMatrix& matrix) const override {
947         return new SkDistantLight(direction(), color());
948     }
onFlattenLight(SkWriteBuffer & buffer) const949     void onFlattenLight(SkWriteBuffer& buffer) const override {
950         write_point3(fDirection, buffer);
951     }
952 
953 private:
954     SkPoint3 fDirection;
955 
956     using INHERITED = SkImageFilterLight;
957 };
958 
959 ///////////////////////////////////////////////////////////////////////////////
960 
961 class SkPointLight : public SkImageFilterLight {
962 public:
SkPointLight(const SkPoint3 & location,SkColor color)963     SkPointLight(const SkPoint3& location, SkColor color)
964      : INHERITED(color), fLocation(location) {}
965 
surfaceToLight(int x,int y,int z,SkScalar surfaceScale) const966     SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const override {
967         SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
968                                             fLocation.fY - SkIntToScalar(y),
969                                             fLocation.fZ - SkIntToScalar(z) * surfaceScale);
970         fast_normalize(&direction);
971         return direction;
972     }
lightColor(const SkPoint3 &) const973     SkPoint3 lightColor(const SkPoint3&) const override { return this->color(); }
type() const974     LightType type() const override { return kPoint_LightType; }
location() const975     const SkPoint3& location() const { return fLocation; }
createGpuLight() const976     std::unique_ptr<GpuLight> createGpuLight() const override {
977 #if defined(SK_GANESH)
978         return std::make_unique<GpuPointLight>();
979 #else
980         SkDEBUGFAIL("Should not call in GPU-less build");
981         return nullptr;
982 #endif
983     }
984 
isEqual(const SkImageFilterLight & other) const985     bool isEqual(const SkImageFilterLight& other) const override {
986         if (other.type() != kPoint_LightType) {
987             return false;
988         }
989         const SkPointLight& o = static_cast<const SkPointLight&>(other);
990         return INHERITED::isEqual(other) &&
991                fLocation == o.fLocation;
992     }
transform(const SkMatrix & matrix) const993     SkImageFilterLight* transform(const SkMatrix& matrix) const override {
994         SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
995         matrix.mapPoints(&location2, 1);
996         // Use X scale and Y scale on Z and average the result
997         SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
998         matrix.mapVectors(&locationZ, 1);
999         SkPoint3 location = SkPoint3::Make(location2.fX,
1000                                            location2.fY,
1001                                            SkScalarAve(locationZ.fX, locationZ.fY));
1002         return new SkPointLight(location, color());
1003     }
1004 
SkPointLight(SkReadBuffer & buffer)1005     SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
1006         fLocation = read_point3(buffer);
1007     }
1008 
1009 protected:
SkPointLight(const SkPoint3 & location,const SkPoint3 & color)1010     SkPointLight(const SkPoint3& location, const SkPoint3& color)
1011      : INHERITED(color), fLocation(location) {}
onFlattenLight(SkWriteBuffer & buffer) const1012     void onFlattenLight(SkWriteBuffer& buffer) const override {
1013         write_point3(fLocation, buffer);
1014     }
1015 
1016 private:
1017     SkPoint3 fLocation;
1018 
1019     using INHERITED = SkImageFilterLight;
1020 };
1021 
1022 ///////////////////////////////////////////////////////////////////////////////
1023 
1024 class SkSpotLight : public SkImageFilterLight {
1025 public:
SkSpotLight(const SkPoint3 & location,const SkPoint3 & target,SkScalar specularExponent,SkScalar cutoffAngle,SkColor color)1026     SkSpotLight(const SkPoint3& location,
1027                 const SkPoint3& target,
1028                 SkScalar specularExponent,
1029                 SkScalar cutoffAngle,
1030                 SkColor color)
1031      : INHERITED(color),
1032        fLocation(location),
1033        fTarget(target),
1034        fSpecularExponent(specularExponent)
1035     {
1036        fS = target - location;
1037        fast_normalize(&fS);
1038        fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
1039        const SkScalar antiAliasThreshold = 0.016f;
1040        fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
1041        fConeScale = SkScalarInvert(antiAliasThreshold);
1042     }
1043 
transform(const SkMatrix & matrix) const1044     SkImageFilterLight* transform(const SkMatrix& matrix) const override {
1045         SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
1046         matrix.mapPoints(&location2, 1);
1047         // Use X scale and Y scale on Z and average the result
1048         SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
1049         matrix.mapVectors(&locationZ, 1);
1050         SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
1051                                            SkScalarAve(locationZ.fX, locationZ.fY));
1052         SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
1053         matrix.mapPoints(&target2, 1);
1054         SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
1055         matrix.mapVectors(&targetZ, 1);
1056         SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
1057                                          SkScalarAve(targetZ.fX, targetZ.fY));
1058         SkPoint3 s = target - location;
1059         fast_normalize(&s);
1060         return new SkSpotLight(location,
1061                                target,
1062                                fSpecularExponent,
1063                                fCosOuterConeAngle,
1064                                fCosInnerConeAngle,
1065                                fConeScale,
1066                                s,
1067                                color());
1068     }
1069 
surfaceToLight(int x,int y,int z,SkScalar surfaceScale) const1070     SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const override {
1071         SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
1072                                             fLocation.fY - SkIntToScalar(y),
1073                                             fLocation.fZ - SkIntToScalar(z) * surfaceScale);
1074         fast_normalize(&direction);
1075         return direction;
1076     }
lightColor(const SkPoint3 & surfaceToLight) const1077     SkPoint3 lightColor(const SkPoint3& surfaceToLight) const override {
1078         SkScalar cosAngle = -surfaceToLight.dot(fS);
1079         SkScalar scale = 0;
1080         if (cosAngle >= fCosOuterConeAngle) {
1081             scale = SkScalarPow(cosAngle, fSpecularExponent);
1082             if (cosAngle < fCosInnerConeAngle) {
1083                 scale *= (cosAngle - fCosOuterConeAngle) * fConeScale;
1084             }
1085         }
1086         return this->color().makeScale(scale);
1087     }
createGpuLight() const1088     std::unique_ptr<GpuLight> createGpuLight() const override {
1089 #if defined(SK_GANESH)
1090         return std::make_unique<GpuSpotLight>();
1091 #else
1092         SkDEBUGFAIL("Should not call in GPU-less build");
1093         return nullptr;
1094 #endif
1095     }
type() const1096     LightType type() const override { return kSpot_LightType; }
location() const1097     const SkPoint3& location() const { return fLocation; }
target() const1098     const SkPoint3& target() const { return fTarget; }
specularExponent() const1099     SkScalar specularExponent() const { return fSpecularExponent; }
cosInnerConeAngle() const1100     SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
cosOuterConeAngle() const1101     SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
coneScale() const1102     SkScalar coneScale() const { return fConeScale; }
s() const1103     const SkPoint3& s() const { return fS; }
1104 
SkSpotLight(SkReadBuffer & buffer)1105     SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
1106         fLocation = read_point3(buffer);
1107         fTarget = read_point3(buffer);
1108         fSpecularExponent = buffer.readScalar();
1109         fCosOuterConeAngle = buffer.readScalar();
1110         fCosInnerConeAngle = buffer.readScalar();
1111         fConeScale = buffer.readScalar();
1112         fS = read_point3(buffer);
1113         buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
1114                         SkScalarIsFinite(fCosOuterConeAngle) &&
1115                         SkScalarIsFinite(fCosInnerConeAngle) &&
1116                         SkScalarIsFinite(fConeScale));
1117     }
1118 protected:
SkSpotLight(const SkPoint3 & location,const SkPoint3 & target,SkScalar specularExponent,SkScalar cosOuterConeAngle,SkScalar cosInnerConeAngle,SkScalar coneScale,const SkPoint3 & s,const SkPoint3 & color)1119     SkSpotLight(const SkPoint3& location,
1120                 const SkPoint3& target,
1121                 SkScalar specularExponent,
1122                 SkScalar cosOuterConeAngle,
1123                 SkScalar cosInnerConeAngle,
1124                 SkScalar coneScale,
1125                 const SkPoint3& s,
1126                 const SkPoint3& color)
1127      : INHERITED(color),
1128        fLocation(location),
1129        fTarget(target),
1130        fSpecularExponent(specularExponent),
1131        fCosOuterConeAngle(cosOuterConeAngle),
1132        fCosInnerConeAngle(cosInnerConeAngle),
1133        fConeScale(coneScale),
1134        fS(s)
1135     {
1136     }
onFlattenLight(SkWriteBuffer & buffer) const1137     void onFlattenLight(SkWriteBuffer& buffer) const override {
1138         write_point3(fLocation, buffer);
1139         write_point3(fTarget, buffer);
1140         buffer.writeScalar(fSpecularExponent);
1141         buffer.writeScalar(fCosOuterConeAngle);
1142         buffer.writeScalar(fCosInnerConeAngle);
1143         buffer.writeScalar(fConeScale);
1144         write_point3(fS, buffer);
1145     }
1146 
isEqual(const SkImageFilterLight & other) const1147     bool isEqual(const SkImageFilterLight& other) const override {
1148         if (other.type() != kSpot_LightType) {
1149             return false;
1150         }
1151 
1152         const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
1153         return INHERITED::isEqual(other) &&
1154                fLocation == o.fLocation &&
1155                fTarget == o.fTarget &&
1156                fSpecularExponent == o.fSpecularExponent &&
1157                fCosOuterConeAngle == o.fCosOuterConeAngle;
1158     }
1159 
1160 private:
1161     SkPoint3 fLocation;
1162     SkPoint3 fTarget;
1163     SkScalar fSpecularExponent;
1164     SkScalar fCosOuterConeAngle;
1165     SkScalar fCosInnerConeAngle;
1166     SkScalar fConeScale;
1167     SkPoint3 fS;
1168 
1169     using INHERITED = SkImageFilterLight;
1170 };
1171 }  // anonymous namespace
1172 
1173 ///////////////////////////////////////////////////////////////////////////////
1174 
flattenLight(SkWriteBuffer & buffer) const1175 void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const {
1176     // Write type first, then baseclass, then subclass.
1177     buffer.writeInt(this->type());
1178     write_point3(fColor, buffer);
1179     this->onFlattenLight(buffer);
1180 }
1181 
UnflattenLight(SkReadBuffer & buffer)1182 /*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) {
1183     SkImageFilterLight::LightType type = buffer.read32LE(SkImageFilterLight::kLast_LightType);
1184 
1185     switch (type) {
1186         // Each of these constructors must first call SkLight's, so we'll read the baseclass
1187         // then subclass, same order as flattenLight.
1188         case SkImageFilterLight::kDistant_LightType:
1189             return new SkDistantLight(buffer);
1190         case SkImageFilterLight::kPoint_LightType:
1191             return new SkPointLight(buffer);
1192         case SkImageFilterLight::kSpot_LightType:
1193             return new SkSpotLight(buffer);
1194         default:
1195             // Should never get here due to prior check of SkSafeRange
1196             SkDEBUGFAIL("Unknown LightType.");
1197             return nullptr;
1198     }
1199 }
1200 ///////////////////////////////////////////////////////////////////////////////
1201 
DistantLitDiffuse(const SkPoint3 & direction,SkColor lightColor,SkScalar surfaceScale,SkScalar kd,sk_sp<SkImageFilter> input,const CropRect & cropRect)1202 sk_sp<SkImageFilter> SkImageFilters::DistantLitDiffuse(
1203         const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
1204         sk_sp<SkImageFilter> input, const CropRect& cropRect) {
1205     sk_sp<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
1206     return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1207                                               std::move(input), cropRect);
1208 }
1209 
PointLitDiffuse(const SkPoint3 & location,SkColor lightColor,SkScalar surfaceScale,SkScalar kd,sk_sp<SkImageFilter> input,const CropRect & cropRect)1210 sk_sp<SkImageFilter> SkImageFilters::PointLitDiffuse(
1211         const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
1212         sk_sp<SkImageFilter> input, const CropRect& cropRect) {
1213     sk_sp<SkImageFilterLight> light(new SkPointLight(location, lightColor));
1214     return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1215                                               std::move(input), cropRect);
1216 }
1217 
SpotLitDiffuse(const SkPoint3 & location,const SkPoint3 & target,SkScalar falloffExponent,SkScalar cutoffAngle,SkColor lightColor,SkScalar surfaceScale,SkScalar kd,sk_sp<SkImageFilter> input,const CropRect & cropRect)1218 sk_sp<SkImageFilter> SkImageFilters::SpotLitDiffuse(
1219         const SkPoint3& location, const SkPoint3& target, SkScalar falloffExponent,
1220         SkScalar cutoffAngle, SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
1221         sk_sp<SkImageFilter> input, const CropRect& cropRect) {
1222     sk_sp<SkImageFilterLight> light(new SkSpotLight(location, target, falloffExponent,
1223                                                     cutoffAngle, lightColor));
1224     return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd,
1225                                               std::move(input), cropRect);
1226 }
1227 
DistantLitSpecular(const SkPoint3 & direction,SkColor lightColor,SkScalar surfaceScale,SkScalar ks,SkScalar shininess,sk_sp<SkImageFilter> input,const CropRect & cropRect)1228 sk_sp<SkImageFilter> SkImageFilters::DistantLitSpecular(
1229         const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale, SkScalar ks,
1230         SkScalar shininess, sk_sp<SkImageFilter> input, const CropRect& cropRect) {
1231     sk_sp<SkImageFilterLight> light(new SkDistantLight(direction, lightColor));
1232     return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shininess,
1233                                                std::move(input), cropRect);
1234 }
1235 
PointLitSpecular(const SkPoint3 & location,SkColor lightColor,SkScalar surfaceScale,SkScalar ks,SkScalar shininess,sk_sp<SkImageFilter> input,const CropRect & cropRect)1236 sk_sp<SkImageFilter> SkImageFilters::PointLitSpecular(
1237         const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale, SkScalar ks,
1238         SkScalar shininess, sk_sp<SkImageFilter> input, const CropRect& cropRect) {
1239     sk_sp<SkImageFilterLight> light(new SkPointLight(location, lightColor));
1240     return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shininess,
1241                                                std::move(input), cropRect);
1242 }
1243 
SpotLitSpecular(const SkPoint3 & location,const SkPoint3 & target,SkScalar falloffExponent,SkScalar cutoffAngle,SkColor lightColor,SkScalar surfaceScale,SkScalar ks,SkScalar shininess,sk_sp<SkImageFilter> input,const CropRect & cropRect)1244 sk_sp<SkImageFilter> SkImageFilters::SpotLitSpecular(
1245         const SkPoint3& location, const SkPoint3& target, SkScalar falloffExponent,
1246         SkScalar cutoffAngle, SkColor lightColor, SkScalar surfaceScale, SkScalar ks,
1247         SkScalar shininess, sk_sp<SkImageFilter> input, const CropRect& cropRect) {
1248     sk_sp<SkImageFilterLight> light(new SkSpotLight(location, target, falloffExponent,
1249                                                     cutoffAngle, lightColor));
1250     return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shininess,
1251                                                std::move(input), cropRect);
1252 }
1253 
SkRegisterLightingImageFilterFlattenables()1254 void SkRegisterLightingImageFilterFlattenables() {
1255     SK_REGISTER_FLATTENABLE(SkDiffuseLightingImageFilter);
1256     SK_REGISTER_FLATTENABLE(SkSpecularLightingImageFilter);
1257 }
1258 
1259 ///////////////////////////////////////////////////////////////////////////////
1260 
Make(sk_sp<SkImageFilterLight> light,SkScalar surfaceScale,SkScalar kd,sk_sp<SkImageFilter> input,const SkRect * cropRect)1261 sk_sp<SkImageFilter> SkDiffuseLightingImageFilter::Make(sk_sp<SkImageFilterLight> light,
1262                                                         SkScalar surfaceScale,
1263                                                         SkScalar kd,
1264                                                         sk_sp<SkImageFilter> input,
1265                                                         const SkRect* cropRect) {
1266     if (!light) {
1267         return nullptr;
1268     }
1269     if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
1270         return nullptr;
1271     }
1272     // According to the spec, kd can be any non-negative number :
1273     // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
1274     if (kd < 0) {
1275         return nullptr;
1276     }
1277     return sk_sp<SkImageFilter>(new SkDiffuseLightingImageFilter(std::move(light), surfaceScale,
1278                                                                  kd, std::move(input), cropRect));
1279 }
1280 
SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light,SkScalar surfaceScale,SkScalar kd,sk_sp<SkImageFilter> input,const SkRect * cropRect)1281 SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light,
1282                                                            SkScalar surfaceScale,
1283                                                            SkScalar kd,
1284                                                            sk_sp<SkImageFilter> input,
1285                                                            const SkRect* cropRect)
1286     : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect)
1287     , fKD(kd) {
1288 }
1289 
CreateProc(SkReadBuffer & buffer)1290 sk_sp<SkFlattenable> SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1291     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1292 
1293     sk_sp<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
1294     SkScalar surfaceScale = buffer.readScalar();
1295     SkScalar kd = buffer.readScalar();
1296 
1297     return Make(std::move(light), surfaceScale, kd, common.getInput(0), common.cropRect());
1298 }
1299 
flatten(SkWriteBuffer & buffer) const1300 void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
1301     this->INHERITED::flatten(buffer);
1302     buffer.writeScalar(fKD);
1303 }
1304 
onFilterImage(const Context & ctx,SkIPoint * offset) const1305 sk_sp<SkSpecialImage> SkDiffuseLightingImageFilter::onFilterImage(const Context& ctx,
1306                                                                   SkIPoint* offset) const {
1307     SkIPoint inputOffset = SkIPoint::Make(0, 0);
1308     sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &inputOffset));
1309     if (!input) {
1310         return nullptr;
1311     }
1312 
1313     const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
1314                                                   input->width(), input->height());
1315     SkIRect bounds;
1316     if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
1317         return nullptr;
1318     }
1319 
1320     offset->fX = bounds.left();
1321     offset->fY = bounds.top();
1322     bounds.offset(-inputOffset);
1323 
1324 #if defined(SK_GANESH)
1325     if (ctx.gpuBacked()) {
1326         SkMatrix matrix(ctx.ctm());
1327         matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY));
1328 
1329         return this->filterImageGPU(ctx, input.get(), bounds, matrix);
1330     }
1331 #endif
1332 
1333     if (bounds.width() < 2 || bounds.height() < 2) {
1334         return nullptr;
1335     }
1336 
1337     SkBitmap inputBM;
1338 
1339     if (!input->getROPixels(&inputBM)) {
1340         return nullptr;
1341     }
1342 
1343     if (inputBM.colorType() != kN32_SkColorType) {
1344         return nullptr;
1345     }
1346 
1347     if (!inputBM.getPixels()) {
1348         return nullptr;
1349     }
1350 
1351     const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height());
1352 
1353     SkBitmap dst;
1354     if (!dst.tryAllocPixels(info)) {
1355         return nullptr;
1356     }
1357 
1358     SkMatrix matrix(ctx.ctm());
1359     matrix.postTranslate(SkIntToScalar(-inputOffset.x()), SkIntToScalar(-inputOffset.y()));
1360 
1361     sk_sp<SkImageFilterLight> transformedLight(light()->transform(matrix));
1362 
1363     DiffuseLightingType lightingType(fKD);
1364     lightBitmap(lightingType,
1365                                                              transformedLight.get(),
1366                                                              inputBM,
1367                                                              &dst,
1368                                                              surfaceScale(),
1369                                                              bounds);
1370 
1371     return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()),
1372                                           dst, ctx.surfaceProps());
1373 }
1374 
1375 #if defined(SK_GANESH)
makeFragmentProcessor(GrSurfaceProxyView view,const SkIPoint & viewOffset,const SkMatrix & matrix,const SkIRect * srcBounds,BoundaryMode boundaryMode,const GrCaps & caps) const1376 std::unique_ptr<GrFragmentProcessor> SkDiffuseLightingImageFilter::makeFragmentProcessor(
1377         GrSurfaceProxyView view,
1378         const SkIPoint& viewOffset,
1379         const SkMatrix& matrix,
1380         const SkIRect* srcBounds,
1381         BoundaryMode boundaryMode,
1382         const GrCaps& caps) const {
1383     SkScalar scale = this->surfaceScale() * 255;
1384     return DiffuseLightingEffect::Make(std::move(view),
1385                                        viewOffset,
1386                                        this->refLight(),
1387                                        scale,
1388                                        matrix,
1389                                        this->kd(),
1390                                        boundaryMode,
1391                                        srcBounds,
1392                                        caps);
1393 }
1394 #endif
1395 
1396 ///////////////////////////////////////////////////////////////////////////////
1397 
Make(sk_sp<SkImageFilterLight> light,SkScalar surfaceScale,SkScalar ks,SkScalar shininess,sk_sp<SkImageFilter> input,const SkRect * cropRect)1398 sk_sp<SkImageFilter> SkSpecularLightingImageFilter::Make(sk_sp<SkImageFilterLight> light,
1399                                                          SkScalar surfaceScale,
1400                                                          SkScalar ks,
1401                                                          SkScalar shininess,
1402                                                          sk_sp<SkImageFilter> input,
1403                                                          const SkRect* cropRect) {
1404     if (!light) {
1405         return nullptr;
1406     }
1407     if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1408         return nullptr;
1409     }
1410     // According to the spec, ks can be any non-negative number :
1411     // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
1412     if (ks < 0) {
1413         return nullptr;
1414     }
1415     return sk_sp<SkImageFilter>(new SkSpecularLightingImageFilter(std::move(light), surfaceScale,
1416                                                                   ks, shininess,
1417                                                                   std::move(input), cropRect));
1418 }
1419 
SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light,SkScalar surfaceScale,SkScalar ks,SkScalar shininess,sk_sp<SkImageFilter> input,const SkRect * cropRect)1420 SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light,
1421                                                              SkScalar surfaceScale,
1422                                                              SkScalar ks,
1423                                                              SkScalar shininess,
1424                                                              sk_sp<SkImageFilter> input,
1425                                                              const SkRect* cropRect)
1426     : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect)
1427     , fKS(ks)
1428     , fShininess(shininess) {
1429 }
1430 
CreateProc(SkReadBuffer & buffer)1431 sk_sp<SkFlattenable> SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1432     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1433     sk_sp<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer));
1434     SkScalar surfaceScale = buffer.readScalar();
1435     SkScalar ks = buffer.readScalar();
1436     SkScalar shine = buffer.readScalar();
1437 
1438     return Make(std::move(light), surfaceScale, ks, shine, common.getInput(0),
1439                 common.cropRect());
1440 }
1441 
flatten(SkWriteBuffer & buffer) const1442 void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
1443     this->INHERITED::flatten(buffer);
1444     buffer.writeScalar(fKS);
1445     buffer.writeScalar(fShininess);
1446 }
1447 
onFilterImage(const Context & ctx,SkIPoint * offset) const1448 sk_sp<SkSpecialImage> SkSpecularLightingImageFilter::onFilterImage(const Context& ctx,
1449                                                                    SkIPoint* offset) const {
1450     SkIPoint inputOffset = SkIPoint::Make(0, 0);
1451     sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &inputOffset));
1452     if (!input) {
1453         return nullptr;
1454     }
1455 
1456     const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
1457                                                   input->width(), input->height());
1458     SkIRect bounds;
1459     if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
1460         return nullptr;
1461     }
1462 
1463     offset->fX = bounds.left();
1464     offset->fY = bounds.top();
1465     bounds.offset(-inputOffset);
1466 
1467 #if defined(SK_GANESH)
1468     if (ctx.gpuBacked()) {
1469         SkMatrix matrix(ctx.ctm());
1470         matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY));
1471 
1472         return this->filterImageGPU(ctx, input.get(), bounds, matrix);
1473     }
1474 #endif
1475 
1476     if (bounds.width() < 2 || bounds.height() < 2) {
1477         return nullptr;
1478     }
1479 
1480     SkBitmap inputBM;
1481 
1482     if (!input->getROPixels(&inputBM)) {
1483         return nullptr;
1484     }
1485 
1486     if (inputBM.colorType() != kN32_SkColorType) {
1487         return nullptr;
1488     }
1489 
1490     if (!inputBM.getPixels()) {
1491         return nullptr;
1492     }
1493 
1494     const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height());
1495 
1496     SkBitmap dst;
1497     if (!dst.tryAllocPixels(info)) {
1498         return nullptr;
1499     }
1500 
1501     SpecularLightingType lightingType(fKS, fShininess);
1502 
1503     SkMatrix matrix(ctx.ctm());
1504     matrix.postTranslate(SkIntToScalar(-inputOffset.x()), SkIntToScalar(-inputOffset.y()));
1505 
1506     sk_sp<SkImageFilterLight> transformedLight(light()->transform(matrix));
1507 
1508     lightBitmap(lightingType,
1509                                                               transformedLight.get(),
1510                                                               inputBM,
1511                                                               &dst,
1512                                                               surfaceScale(),
1513                                                               bounds);
1514 
1515     return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()), dst,
1516                                           ctx.surfaceProps());
1517 }
1518 
1519 #if defined(SK_GANESH)
makeFragmentProcessor(GrSurfaceProxyView view,const SkIPoint & viewOffset,const SkMatrix & matrix,const SkIRect * srcBounds,BoundaryMode boundaryMode,const GrCaps & caps) const1520 std::unique_ptr<GrFragmentProcessor> SkSpecularLightingImageFilter::makeFragmentProcessor(
1521         GrSurfaceProxyView view,
1522         const SkIPoint& viewOffset,
1523         const SkMatrix& matrix,
1524         const SkIRect* srcBounds,
1525         BoundaryMode boundaryMode,
1526         const GrCaps& caps) const {
1527     SkScalar scale = this->surfaceScale() * 255;
1528     return SpecularLightingEffect::Make(std::move(view),
1529                                         viewOffset,
1530                                         this->refLight(),
1531                                         scale,
1532                                         matrix,
1533                                         this->ks(),
1534                                         this->shininess(),
1535                                         boundaryMode,
1536                                         srcBounds,
1537                                         caps);
1538 }
1539 #endif
1540 
1541 ///////////////////////////////////////////////////////////////////////////////
1542 
1543 #if defined(SK_GANESH)
1544 
emitNormalFunc(BoundaryMode mode,const char * pointToNormalName,const char * sobelFuncName)1545 static SkString emitNormalFunc(BoundaryMode mode,
1546                                const char* pointToNormalName,
1547                                const char* sobelFuncName) {
1548     SkString result;
1549     switch (mode) {
1550     case kTopLeft_BoundaryMode:
1551         result.printf("return %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),"
1552                       "          %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),"
1553                       "          surfaceScale);",
1554                       pointToNormalName, sobelFuncName, gTwoThirds,
1555                                          sobelFuncName, gTwoThirds);
1556         break;
1557     case kTop_BoundaryMode:
1558         result.printf("return %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),"
1559                       "          %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),"
1560                       "          surfaceScale);",
1561                       pointToNormalName, sobelFuncName, gOneThird,
1562                                          sobelFuncName, gOneHalf);
1563         break;
1564     case kTopRight_BoundaryMode:
1565         result.printf("return %s(%s( 0.0,  0.0, m[3], m[4], m[6], m[7], %g),"
1566                       "          %s(m[3], m[6], m[4], m[7],  0.0,  0.0, %g),"
1567                       "          surfaceScale);",
1568                       pointToNormalName, sobelFuncName, gTwoThirds,
1569                                          sobelFuncName, gTwoThirds);
1570         break;
1571     case kLeft_BoundaryMode:
1572         result.printf("return %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),"
1573                       "          %s( 0.0,  0.0, m[1], m[7], m[2], m[8], %g),"
1574                       "          surfaceScale);",
1575                       pointToNormalName, sobelFuncName, gOneHalf,
1576                                          sobelFuncName, gOneThird);
1577         break;
1578     case kInterior_BoundaryMode:
1579         result.printf("return %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),"
1580                       "          %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),"
1581                       "          surfaceScale);",
1582                       pointToNormalName, sobelFuncName, gOneQuarter,
1583                                          sobelFuncName, gOneQuarter);
1584         break;
1585     case kRight_BoundaryMode:
1586         result.printf("return %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),"
1587                       "          %s(m[0], m[6], m[1], m[7],  0.0,  0.0, %g),"
1588                       "          surfaceScale);",
1589                       pointToNormalName, sobelFuncName, gOneHalf,
1590                                          sobelFuncName, gOneThird);
1591         break;
1592     case kBottomLeft_BoundaryMode:
1593         result.printf("return %s(%s(m[1], m[2], m[4], m[5],  0.0,  0.0, %g),"
1594                       "          %s( 0.0,  0.0, m[1], m[4], m[2], m[5], %g),"
1595                       "          surfaceScale);",
1596                       pointToNormalName, sobelFuncName, gTwoThirds,
1597                                          sobelFuncName, gTwoThirds);
1598         break;
1599     case kBottom_BoundaryMode:
1600         result.printf("return %s(%s(m[0], m[2], m[3], m[5],  0.0,  0.0, %g),"
1601                       "          %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),"
1602                       "          surfaceScale);",
1603                       pointToNormalName, sobelFuncName, gOneThird,
1604                                          sobelFuncName, gOneHalf);
1605         break;
1606     case kBottomRight_BoundaryMode:
1607         result.printf("return %s(%s(m[0], m[1], m[3], m[4],  0.0,  0.0, %g),"
1608                       "          %s(m[0], m[3], m[1], m[4],  0.0,  0.0, %g),"
1609                       "          surfaceScale);",
1610                       pointToNormalName, sobelFuncName, gTwoThirds,
1611                                          sobelFuncName, gTwoThirds);
1612         break;
1613     default:
1614         SkASSERT(false);
1615         break;
1616     }
1617     return result;
1618 }
1619 
1620 namespace {
1621 class LightingEffect::ImplBase : public ProgramImpl {
1622 public:
1623     void emitCode(EmitArgs&) override;
1624 
1625 protected:
1626     /**
1627      * Subclasses of LightingImpl must call INHERITED::onSetData();
1628      */
1629     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1630 
1631     virtual void emitLightFunc(const GrFragmentProcessor*,
1632                                GrGLSLUniformHandler*,
1633                                GrGLSLFPFragmentBuilder*,
1634                                SkString* funcName) = 0;
1635 
1636 private:
1637     UniformHandle             fSurfaceScaleUni;
1638     std::unique_ptr<GpuLight> fLight;
1639 };
1640 
1641 ///////////////////////////////////////////////////////////////////////////////
1642 
1643 class DiffuseLightingEffect::Impl : public ImplBase {
1644 public:
1645     void emitLightFunc(const GrFragmentProcessor*,
1646                        GrGLSLUniformHandler*,
1647                        GrGLSLFPFragmentBuilder*,
1648                        SkString* funcName) override;
1649 
1650 private:
1651     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1652 
1653     using INHERITED = ImplBase;
1654 
1655     UniformHandle   fKDUni;
1656 };
1657 
1658 ///////////////////////////////////////////////////////////////////////////////
1659 
1660 class SpecularLightingEffect::Impl : public ImplBase {
1661 public:
1662     void emitLightFunc(const GrFragmentProcessor*,
1663                        GrGLSLUniformHandler*,
1664                        GrGLSLFPFragmentBuilder*,
1665                        SkString* funcName) override;
1666 
1667 private:
1668     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1669 
1670     using INHERITED = ImplBase;
1671 
1672     UniformHandle   fKSUni;
1673     UniformHandle   fShininessUni;
1674 };
1675 }  // anonymous namespace
1676 
1677 ///////////////////////////////////////////////////////////////////////////////
1678 
LightingEffect(ClassID classID,GrSurfaceProxyView view,const SkIPoint & viewOffset,sk_sp<const SkImageFilterLight> light,SkScalar surfaceScale,const SkMatrix & matrix,BoundaryMode boundaryMode,const SkIRect * srcBounds,const GrCaps & caps)1679 LightingEffect::LightingEffect(ClassID classID,
1680                                GrSurfaceProxyView view,
1681                                const SkIPoint& viewOffset,
1682                                sk_sp<const SkImageFilterLight> light,
1683                                SkScalar surfaceScale,
1684                                const SkMatrix& matrix,
1685                                BoundaryMode boundaryMode,
1686                                const SkIRect* srcBounds,
1687                                const GrCaps& caps)
1688         // Perhaps this could advertise the opaque or coverage-as-alpha optimizations?
1689         : INHERITED(classID, kNone_OptimizationFlags)
1690         , fLight(std::move(light))
1691         , fSurfaceScale(surfaceScale)
1692         , fFilterMatrix(matrix)
1693         , fBoundaryMode(boundaryMode) {
1694     static constexpr GrSamplerState kSampler(GrSamplerState::WrapMode::kClampToBorder,
1695                                              GrSamplerState::Filter::kNearest);
1696     std::unique_ptr<GrFragmentProcessor> child;
1697     if (srcBounds) {
1698         SkRect offsetSrcBounds = SkRect::Make(*srcBounds);
1699         offsetSrcBounds.offset(viewOffset.fX, viewOffset.fY);
1700         child = GrTextureEffect::MakeSubset(std::move(view), kPremul_SkAlphaType,
1701                                             SkMatrix::Translate(viewOffset.fX, viewOffset.fY),
1702                                             kSampler, offsetSrcBounds, caps);
1703     } else {
1704         child = GrTextureEffect::Make(std::move(view), kPremul_SkAlphaType,
1705                                       SkMatrix::Translate(viewOffset.fX, viewOffset.fY),
1706                                       kSampler, caps);
1707     }
1708     this->registerChild(std::move(child), SkSL::SampleUsage::Explicit());
1709     this->setUsesSampleCoordsDirectly();
1710 }
1711 
LightingEffect(const LightingEffect & that)1712 LightingEffect::LightingEffect(const LightingEffect& that)
1713         : INHERITED(that)
1714         , fLight(that.fLight)
1715         , fSurfaceScale(that.fSurfaceScale)
1716         , fFilterMatrix(that.fFilterMatrix)
1717         , fBoundaryMode(that.fBoundaryMode) {}
1718 
onIsEqual(const GrFragmentProcessor & sBase) const1719 bool LightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
1720     const LightingEffect& s = sBase.cast<LightingEffect>();
1721     return fLight->isEqual(*s.fLight) &&
1722            fSurfaceScale == s.fSurfaceScale &&
1723            fBoundaryMode == s.fBoundaryMode;
1724 }
1725 
1726 ///////////////////////////////////////////////////////////////////////////////
1727 
DiffuseLightingEffect(GrSurfaceProxyView view,const SkIPoint & viewOffset,sk_sp<const SkImageFilterLight> light,SkScalar surfaceScale,const SkMatrix & matrix,SkScalar kd,BoundaryMode boundaryMode,const SkIRect * srcBounds,const GrCaps & caps)1728 DiffuseLightingEffect::DiffuseLightingEffect(GrSurfaceProxyView view,
1729                                              const SkIPoint& viewOffset,
1730                                              sk_sp<const SkImageFilterLight> light,
1731                                              SkScalar surfaceScale,
1732                                              const SkMatrix& matrix,
1733                                              SkScalar kd,
1734                                              BoundaryMode boundaryMode,
1735                                              const SkIRect* srcBounds,
1736                                              const GrCaps& caps)
1737         : INHERITED(kGrDiffuseLightingEffect_ClassID,
1738                     std::move(view),
1739                     viewOffset,
1740                     std::move(light),
1741                     surfaceScale,
1742                     matrix,
1743                     boundaryMode,
1744                     srcBounds,
1745                     caps)
1746         , fKD(kd) {}
1747 
DiffuseLightingEffect(const DiffuseLightingEffect & that)1748 DiffuseLightingEffect::DiffuseLightingEffect(const DiffuseLightingEffect& that)
1749         : INHERITED(that), fKD(that.fKD) {}
1750 
onIsEqual(const GrFragmentProcessor & sBase) const1751 bool DiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
1752     const DiffuseLightingEffect& s = sBase.cast<DiffuseLightingEffect>();
1753     return INHERITED::onIsEqual(sBase) && fKD == s.fKD;
1754 }
1755 
onMakeProgramImpl() const1756 std::unique_ptr<GrFragmentProcessor::ProgramImpl> DiffuseLightingEffect::onMakeProgramImpl() const {
1757     return std::make_unique<Impl>();
1758 }
1759 
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(DiffuseLightingEffect)1760 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(DiffuseLightingEffect)
1761 
1762 #if GR_TEST_UTILS
1763 
1764 static SkPoint3 random_point3(SkRandom* random) {
1765     return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
1766                           SkScalarToFloat(random->nextSScalar1()),
1767                           SkScalarToFloat(random->nextSScalar1()));
1768 }
1769 
create_random_light(SkRandom * random)1770 static SkImageFilterLight* create_random_light(SkRandom* random) {
1771     int type = random->nextULessThan(3);
1772     switch (type) {
1773         case 0: {
1774             return new SkDistantLight(random_point3(random), random->nextU());
1775         }
1776         case 1: {
1777             return new SkPointLight(random_point3(random), random->nextU());
1778         }
1779         case 2: {
1780             return new SkSpotLight(random_point3(random), random_point3(random),
1781                                    random->nextUScalar1(), random->nextUScalar1(), random->nextU());
1782         }
1783         default:
1784             SK_ABORT("Unexpected value.");
1785     }
1786 }
1787 
TestCreate(GrProcessorTestData * d)1788 std::unique_ptr<GrFragmentProcessor> DiffuseLightingEffect::TestCreate(GrProcessorTestData* d) {
1789     auto [view, ct, at] = d->randomView();
1790     SkScalar surfaceScale = d->fRandom->nextSScalar1();
1791     SkScalar kd = d->fRandom->nextUScalar1();
1792     sk_sp<SkImageFilterLight> light(create_random_light(d->fRandom));
1793     SkMatrix matrix;
1794     for (int i = 0; i < 9; i++) {
1795         matrix[i] = d->fRandom->nextUScalar1();
1796     }
1797 
1798     uint32_t boundsX = d->fRandom->nextRangeU(0, view.width());
1799     uint32_t boundsY = d->fRandom->nextRangeU(0, view.height());
1800     uint32_t boundsW = d->fRandom->nextRangeU(0, view.width());
1801     uint32_t boundsH = d->fRandom->nextRangeU(0, view.height());
1802     SkIRect srcBounds = SkIRect::MakeXYWH(boundsX, boundsY, boundsW, boundsH);
1803     BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
1804 
1805     return DiffuseLightingEffect::Make(std::move(view),
1806                                        SkIPoint(),
1807                                        std::move(light),
1808                                        surfaceScale,
1809                                        matrix,
1810                                        kd,
1811                                        mode,
1812                                        &srcBounds,
1813                                        *d->caps());
1814 }
1815 #endif
1816 
1817 
1818 ///////////////////////////////////////////////////////////////////////////////
1819 
emitCode(EmitArgs & args)1820 void LightingEffect::ImplBase::emitCode(EmitArgs& args) {
1821     const LightingEffect& le = args.fFp.cast<LightingEffect>();
1822     if (!fLight) {
1823         fLight = le.light()->createGpuLight();
1824     }
1825 
1826     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1827     fSurfaceScaleUni = uniformHandler->addUniform(&le,
1828                                                   kFragment_GrShaderFlag,
1829                                                   SkSLType::kHalf, "SurfaceScale");
1830     fLight->emitLightColorUniform(&le, uniformHandler);
1831     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
1832     SkString lightFunc;
1833     this->emitLightFunc(&le, uniformHandler, fragBuilder, &lightFunc);
1834     const GrShaderVar gSobelArgs[] = {
1835         GrShaderVar("a", SkSLType::kHalf),
1836         GrShaderVar("b", SkSLType::kHalf),
1837         GrShaderVar("c", SkSLType::kHalf),
1838         GrShaderVar("d", SkSLType::kHalf),
1839         GrShaderVar("e", SkSLType::kHalf),
1840         GrShaderVar("f", SkSLType::kHalf),
1841         GrShaderVar("scale", SkSLType::kHalf),
1842     };
1843 
1844     SkString sobelFuncName = fragBuilder->getMangledFunctionName("sobel");
1845     fragBuilder->emitFunction(SkSLType::kHalf,
1846                               sobelFuncName.c_str(),
1847                               {gSobelArgs, std::size(gSobelArgs)},
1848                               "return (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;");
1849     const GrShaderVar gPointToNormalArgs[] = {
1850         GrShaderVar("x", SkSLType::kHalf),
1851         GrShaderVar("y", SkSLType::kHalf),
1852         GrShaderVar("scale", SkSLType::kHalf),
1853     };
1854     SkString pointToNormalName = fragBuilder->getMangledFunctionName("pointToNormal");
1855     fragBuilder->emitFunction(SkSLType::kHalf3,
1856                               pointToNormalName.c_str(),
1857                               {gPointToNormalArgs, std::size(gPointToNormalArgs)},
1858                               "return normalize(half3(-x * scale, -y * scale, 1));");
1859 
1860     const GrShaderVar gInteriorNormalArgs[] = {
1861         GrShaderVar("m", SkSLType::kHalf, 9),
1862         GrShaderVar("surfaceScale", SkSLType::kHalf),
1863     };
1864     SkString normalBody = emitNormalFunc(le.boundaryMode(),
1865                                          pointToNormalName.c_str(),
1866                                          sobelFuncName.c_str());
1867     SkString normalName = fragBuilder->getMangledFunctionName("normal");
1868     fragBuilder->emitFunction(SkSLType::kHalf3,
1869                               normalName.c_str(),
1870                               {gInteriorNormalArgs, std::size(gInteriorNormalArgs)},
1871                               normalBody.c_str());
1872 
1873     fragBuilder->codeAppendf("float2 coord = %s;", args.fSampleCoord);
1874     fragBuilder->codeAppend("half m[9];");
1875 
1876     const char* surfScale = uniformHandler->getUniformCStr(fSurfaceScaleUni);
1877 
1878     int index = 0;
1879     for (int dy = -1; dy <= 1; ++dy) {
1880         for (int dx = -1; dx <= 1; ++dx) {
1881             SkString texCoords;
1882             texCoords.appendf("coord + half2(%d, %d)", dx, dy);
1883             auto sample = this->invokeChild(0, args, texCoords.c_str());
1884             fragBuilder->codeAppendf("m[%d] = %s.a;", index, sample.c_str());
1885             index++;
1886         }
1887     }
1888     fragBuilder->codeAppend("half3 surfaceToLight = ");
1889     SkString arg;
1890     arg.appendf("%s * m[4]", surfScale);
1891     fLight->emitSurfaceToLight(&le, uniformHandler, fragBuilder, arg.c_str());
1892     fragBuilder->codeAppend(";");
1893     fragBuilder->codeAppendf("return %s(%s(m, %s), surfaceToLight, ",
1894                              lightFunc.c_str(), normalName.c_str(), surfScale);
1895     fLight->emitLightColor(&le, uniformHandler, fragBuilder, "surfaceToLight");
1896     fragBuilder->codeAppend(");");
1897 }
1898 
onSetData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & proc)1899 void LightingEffect::ImplBase::onSetData(const GrGLSLProgramDataManager& pdman,
1900                                          const GrFragmentProcessor& proc) {
1901     const LightingEffect& lighting = proc.cast<LightingEffect>();
1902     if (!fLight) {
1903         fLight = lighting.light()->createGpuLight();
1904     }
1905 
1906     pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
1907     sk_sp<SkImageFilterLight> transformedLight(
1908             lighting.light()->transform(lighting.filterMatrix()));
1909     fLight->setData(pdman, transformedLight.get());
1910 }
1911 
1912 ///////////////////////////////////////////////////////////////////////////////
1913 
1914 ///////////////////////////////////////////////////////////////////////////////
1915 
emitLightFunc(const GrFragmentProcessor * owner,GrGLSLUniformHandler * uniformHandler,GrGLSLFPFragmentBuilder * fragBuilder,SkString * funcName)1916 void DiffuseLightingEffect::Impl::emitLightFunc(const GrFragmentProcessor* owner,
1917                                                 GrGLSLUniformHandler* uniformHandler,
1918                                                 GrGLSLFPFragmentBuilder* fragBuilder,
1919                                                 SkString* funcName) {
1920     const char* kd;
1921     fKDUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, SkSLType::kHalf, "KD", &kd);
1922 
1923     const GrShaderVar gLightArgs[] = {
1924         GrShaderVar("normal", SkSLType::kHalf3),
1925         GrShaderVar("surfaceToLight", SkSLType::kHalf3),
1926         GrShaderVar("lightColor", SkSLType::kHalf3)
1927     };
1928     SkString lightBody;
1929     lightBody.appendf("half colorScale = %s * dot(normal, surfaceToLight);", kd);
1930     lightBody.appendf("return half4(saturate(lightColor * colorScale), 1.0);");
1931     *funcName = fragBuilder->getMangledFunctionName("light");
1932     fragBuilder->emitFunction(SkSLType::kHalf4,
1933                               funcName->c_str(),
1934                               {gLightArgs, std::size(gLightArgs)},
1935                               lightBody.c_str());
1936 }
1937 
onSetData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & proc)1938 void DiffuseLightingEffect::Impl::onSetData(const GrGLSLProgramDataManager& pdman,
1939                                             const GrFragmentProcessor& proc) {
1940     INHERITED::onSetData(pdman, proc);
1941     const DiffuseLightingEffect& diffuse = proc.cast<DiffuseLightingEffect>();
1942     pdman.set1f(fKDUni, diffuse.fKD);
1943 }
1944 
1945 ///////////////////////////////////////////////////////////////////////////////
1946 
SpecularLightingEffect(GrSurfaceProxyView view,const SkIPoint & viewOffset,sk_sp<const SkImageFilterLight> light,SkScalar surfaceScale,const SkMatrix & matrix,SkScalar ks,SkScalar shininess,BoundaryMode boundaryMode,const SkIRect * srcBounds,const GrCaps & caps)1947 SpecularLightingEffect::SpecularLightingEffect(GrSurfaceProxyView view,
1948                                                const SkIPoint& viewOffset,
1949                                                sk_sp<const SkImageFilterLight> light,
1950                                                SkScalar surfaceScale,
1951                                                const SkMatrix& matrix,
1952                                                SkScalar ks,
1953                                                SkScalar shininess,
1954                                                BoundaryMode boundaryMode,
1955                                                const SkIRect* srcBounds,
1956                                                const GrCaps& caps)
1957         : INHERITED(kGrSpecularLightingEffect_ClassID,
1958                     std::move(view),
1959                     viewOffset,
1960                     std::move(light),
1961                     surfaceScale,
1962                     matrix,
1963                     boundaryMode,
1964                     srcBounds,
1965                     caps)
1966         , fKS(ks)
1967         , fShininess(shininess) {}
1968 
SpecularLightingEffect(const SpecularLightingEffect & that)1969 SpecularLightingEffect::SpecularLightingEffect(const SpecularLightingEffect& that)
1970         : INHERITED(that), fKS(that.fKS), fShininess(that.fShininess) {}
1971 
onIsEqual(const GrFragmentProcessor & sBase) const1972 bool SpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
1973     const SpecularLightingEffect& s = sBase.cast<SpecularLightingEffect>();
1974     return INHERITED::onIsEqual(sBase) && this->fKS == s.fKS && this->fShininess == s.fShininess;
1975 }
1976 
1977 std::unique_ptr<GrFragmentProcessor::ProgramImpl>
onMakeProgramImpl() const1978 SpecularLightingEffect::onMakeProgramImpl() const { return std::make_unique<Impl>(); }
1979 
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(SpecularLightingEffect)1980 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(SpecularLightingEffect)
1981 
1982 #if GR_TEST_UTILS
1983 std::unique_ptr<GrFragmentProcessor> SpecularLightingEffect::TestCreate(GrProcessorTestData* d) {
1984     auto [view, ct, at] = d->randomView();
1985     SkScalar surfaceScale = d->fRandom->nextSScalar1();
1986     SkScalar ks = d->fRandom->nextUScalar1();
1987     SkScalar shininess = d->fRandom->nextUScalar1();
1988     sk_sp<SkImageFilterLight> light(create_random_light(d->fRandom));
1989     SkMatrix matrix;
1990     for (int i = 0; i < 9; i++) {
1991         matrix[i] = d->fRandom->nextUScalar1();
1992     }
1993     BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount);
1994 
1995     uint32_t boundsX = d->fRandom->nextRangeU(0, view.width());
1996     uint32_t boundsY = d->fRandom->nextRangeU(0, view.height());
1997     uint32_t boundsW = d->fRandom->nextRangeU(0, view.width());
1998     uint32_t boundsH = d->fRandom->nextRangeU(0, view.height());
1999     SkIRect srcBounds = SkIRect::MakeXYWH(boundsX, boundsY, boundsW, boundsH);
2000 
2001     return SpecularLightingEffect::Make(std::move(view),
2002                                         SkIPoint(),
2003                                         std::move(light),
2004                                         surfaceScale,
2005                                         matrix,
2006                                         ks,
2007                                         shininess,
2008                                         mode,
2009                                         &srcBounds,
2010                                         *d->caps());
2011 }
2012 #endif
2013 
2014 ///////////////////////////////////////////////////////////////////////////////
2015 
emitLightFunc(const GrFragmentProcessor * owner,GrGLSLUniformHandler * uniformHandler,GrGLSLFPFragmentBuilder * fragBuilder,SkString * funcName)2016 void SpecularLightingEffect::Impl::emitLightFunc(const GrFragmentProcessor* owner,
2017                                                  GrGLSLUniformHandler* uniformHandler,
2018                                                  GrGLSLFPFragmentBuilder* fragBuilder,
2019                                                  SkString* funcName) {
2020     const char* ks;
2021     const char* shininess;
2022 
2023     fKSUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, SkSLType::kHalf, "KS", &ks);
2024     fShininessUni = uniformHandler->addUniform(owner,
2025                                                kFragment_GrShaderFlag,
2026                                                SkSLType::kHalf,
2027                                                "Shininess",
2028                                                &shininess);
2029 
2030     const GrShaderVar gLightArgs[] = {
2031         GrShaderVar("normal", SkSLType::kHalf3),
2032         GrShaderVar("surfaceToLight", SkSLType::kHalf3),
2033         GrShaderVar("lightColor", SkSLType::kHalf3)
2034     };
2035     SkString lightBody;
2036     lightBody.appendf("half3 halfDir = half3(normalize(surfaceToLight + half3(0, 0, 1)));");
2037     lightBody.appendf("half colorScale = half(%s * pow(dot(normal, halfDir), %s));",
2038                       ks, shininess);
2039     lightBody.appendf("half3 color = saturate(lightColor * colorScale);");
2040     lightBody.appendf("return half4(color, max(max(color.r, color.g), color.b));");
2041     *funcName = fragBuilder->getMangledFunctionName("light");
2042     fragBuilder->emitFunction(SkSLType::kHalf4,
2043                               funcName->c_str(),
2044                               {gLightArgs, std::size(gLightArgs)},
2045                               lightBody.c_str());
2046 }
2047 
onSetData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & effect)2048 void SpecularLightingEffect::Impl::onSetData(const GrGLSLProgramDataManager& pdman,
2049                                              const GrFragmentProcessor& effect) {
2050     INHERITED::onSetData(pdman, effect);
2051     const SpecularLightingEffect& spec = effect.cast<SpecularLightingEffect>();
2052     pdman.set1f(fKSUni, spec.fKS);
2053     pdman.set1f(fShininessUni, spec.fShininess);
2054 }
2055 
2056 ///////////////////////////////////////////////////////////////////////////////
emitLightColorUniform(const GrFragmentProcessor * owner,GrGLSLUniformHandler * uniformHandler)2057 void GpuLight::emitLightColorUniform(const GrFragmentProcessor* owner,
2058                                      GrGLSLUniformHandler* uniformHandler) {
2059     fColorUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, SkSLType::kHalf3,
2060                                            "LightColor");
2061 }
2062 
emitLightColor(const GrFragmentProcessor * owner,GrGLSLUniformHandler * uniformHandler,GrGLSLFPFragmentBuilder * fragBuilder,const char * surfaceToLight)2063 void GpuLight::emitLightColor(const GrFragmentProcessor* owner,
2064                               GrGLSLUniformHandler* uniformHandler,
2065                               GrGLSLFPFragmentBuilder* fragBuilder,
2066                               const char* surfaceToLight) {
2067     fragBuilder->codeAppend(uniformHandler->getUniformCStr(this->lightColorUni()));
2068 }
2069 
setData(const GrGLSLProgramDataManager & pdman,const SkImageFilterLight * light) const2070 void GpuLight::setData(const GrGLSLProgramDataManager& pdman,
2071                        const SkImageFilterLight* light) const {
2072     setUniformPoint3(pdman, fColorUni,
2073                      light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
2074 }
2075 
2076 ///////////////////////////////////////////////////////////////////////////////
2077 
setData(const GrGLSLProgramDataManager & pdman,const SkImageFilterLight * light) const2078 void GpuDistantLight::setData(const GrGLSLProgramDataManager& pdman,
2079                               const SkImageFilterLight* light) const {
2080     INHERITED::setData(pdman, light);
2081     SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType);
2082     const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
2083     setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
2084 }
2085 
emitSurfaceToLight(const GrFragmentProcessor * owner,GrGLSLUniformHandler * uniformHandler,GrGLSLFPFragmentBuilder * fragBuilder,const char * z)2086 void GpuDistantLight::emitSurfaceToLight(const GrFragmentProcessor* owner,
2087                                          GrGLSLUniformHandler* uniformHandler,
2088                                          GrGLSLFPFragmentBuilder* fragBuilder,
2089                                          const char* z) {
2090     const char* dir;
2091     fDirectionUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, SkSLType::kHalf3,
2092                                                "LightDirection", &dir);
2093     fragBuilder->codeAppend(dir);
2094 }
2095 
2096 ///////////////////////////////////////////////////////////////////////////////
2097 
setData(const GrGLSLProgramDataManager & pdman,const SkImageFilterLight * light) const2098 void GpuPointLight::setData(const GrGLSLProgramDataManager& pdman,
2099                             const SkImageFilterLight* light) const {
2100     INHERITED::setData(pdman, light);
2101     SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType);
2102     const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
2103     setUniformPoint3(pdman, fLocationUni, pointLight->location());
2104 }
2105 
emitSurfaceToLight(const GrFragmentProcessor * owner,GrGLSLUniformHandler * uniformHandler,GrGLSLFPFragmentBuilder * fragBuilder,const char * z)2106 void GpuPointLight::emitSurfaceToLight(const GrFragmentProcessor* owner,
2107                                        GrGLSLUniformHandler* uniformHandler,
2108                                        GrGLSLFPFragmentBuilder* fragBuilder,
2109                                        const char* z) {
2110     const char* loc;
2111     fLocationUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, SkSLType::kHalf3,
2112                                               "LightLocation", &loc);
2113     fragBuilder->codeAppendf("normalize(%s - half3(sk_FragCoord.xy, %s))",
2114                              loc, z);
2115 }
2116 
2117 ///////////////////////////////////////////////////////////////////////////////
2118 
setData(const GrGLSLProgramDataManager & pdman,const SkImageFilterLight * light) const2119 void GpuSpotLight::setData(const GrGLSLProgramDataManager& pdman,
2120                            const SkImageFilterLight* light) const {
2121     INHERITED::setData(pdman, light);
2122     SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType);
2123     const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
2124     setUniformPoint3(pdman, fLocationUni, spotLight->location());
2125     pdman.set1f(fExponentUni, spotLight->specularExponent());
2126     pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
2127     pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
2128     pdman.set1f(fConeScaleUni, spotLight->coneScale());
2129     setUniformNormal3(pdman, fSUni, spotLight->s());
2130 }
2131 
emitSurfaceToLight(const GrFragmentProcessor * owner,GrGLSLUniformHandler * uniformHandler,GrGLSLFPFragmentBuilder * fragBuilder,const char * z)2132 void GpuSpotLight::emitSurfaceToLight(const GrFragmentProcessor* owner,
2133                                       GrGLSLUniformHandler* uniformHandler,
2134                                       GrGLSLFPFragmentBuilder* fragBuilder,
2135                                       const char* z) {
2136     const char* location;
2137     fLocationUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, SkSLType::kHalf3,
2138                                               "LightLocation", &location);
2139 
2140     fragBuilder->codeAppendf("normalize(%s - half3(sk_FragCoord.xy, %s))",
2141                              location, z);
2142 }
2143 
emitLightColor(const GrFragmentProcessor * owner,GrGLSLUniformHandler * uniformHandler,GrGLSLFPFragmentBuilder * fragBuilder,const char * surfaceToLight)2144 void GpuSpotLight::emitLightColor(const GrFragmentProcessor* owner,
2145                                   GrGLSLUniformHandler* uniformHandler,
2146                                   GrGLSLFPFragmentBuilder* fragBuilder,
2147                                   const char* surfaceToLight) {
2148     const char* color = uniformHandler->getUniformCStr(this->lightColorUni()); // created by parent class.
2149 
2150     const char* exponent;
2151     const char* cosInner;
2152     const char* cosOuter;
2153     const char* coneScale;
2154     const char* s;
2155     fExponentUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, SkSLType::kHalf,
2156                                               "Exponent", &exponent);
2157     fCosInnerConeAngleUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag,
2158                                                        SkSLType::kHalf, "CosInnerConeAngle",
2159                                                        &cosInner);
2160     fCosOuterConeAngleUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag,
2161                                                        SkSLType::kHalf, "CosOuterConeAngle",
2162                                                        &cosOuter);
2163     fConeScaleUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, SkSLType::kHalf,
2164                                                "ConeScale", &coneScale);
2165     fSUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, SkSLType::kHalf3, "S", &s);
2166 
2167     const GrShaderVar gLightColorArgs[] = {
2168         GrShaderVar("surfaceToLight", SkSLType::kHalf3)
2169     };
2170     SkString lightColorBody;
2171     lightColorBody.appendf("half cosAngle = -dot(surfaceToLight, %s);", s);
2172     lightColorBody.appendf("if (cosAngle < %s) {", cosOuter);
2173     lightColorBody.appendf("return half3(0);");
2174     lightColorBody.appendf("}");
2175     lightColorBody.appendf("half scale = pow(cosAngle, %s);", exponent);
2176     lightColorBody.appendf("if (cosAngle < %s) {", cosInner);
2177     lightColorBody.appendf("return %s * scale * (cosAngle - %s) * %s;",
2178                            color, cosOuter, coneScale);
2179     lightColorBody.appendf("}");
2180     lightColorBody.appendf("return %s * scale;", color);
2181     fLightColorFunc = fragBuilder->getMangledFunctionName("lightColor");
2182     fragBuilder->emitFunction(SkSLType::kHalf3,
2183                               fLightColorFunc.c_str(),
2184                               {gLightColorArgs, std::size(gLightColorArgs)},
2185                               lightColorBody.c_str());
2186 
2187     fragBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
2188 }
2189 
2190 #endif
2191