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