blob: 26bc033b5840392a332f3b27a799b7775c475221 [file] [log] [blame]
rileya@google.com1c6d64b2012-07-27 15:49:05 +00001/*
2 * Copyright 2012 Google Inc.
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#ifndef SkGradientShaderPriv_DEFINED
9#define SkGradientShaderPriv_DEFINED
10
reeda6cac4c2014-08-21 10:50:25 -070011#include "SkGradientBitmapCache.h"
rileya@google.com1c6d64b2012-07-27 15:49:05 +000012#include "SkGradientShader.h"
Hal Canary95e3c052017-01-11 12:44:43 -050013
Herb Derby83e939b2017-02-07 14:25:11 -050014#include "SkArenaAlloc.h"
Hal Canary95e3c052017-01-11 12:44:43 -050015#include "SkAutoMalloc.h"
rileya@google.com1c6d64b2012-07-27 15:49:05 +000016#include "SkClampRange.h"
Cary Clarka4083c92017-09-15 11:59:23 -040017#include "SkColorData.h"
brianosmanb9c51372016-09-15 11:09:45 -070018#include "SkColorSpace.h"
Cary Clark9480d822017-10-19 18:01:13 -040019#include "SkMatrixPriv.h"
Kevin Lubickc456b732017-01-11 17:21:57 +000020#include "SkOnce.h"
Mike Kleina3771842017-05-04 19:38:48 -040021#include "SkPM4fPriv.h"
22#include "SkRasterPipeline.h"
Hal Canary95e3c052017-01-11 12:44:43 -050023#include "SkReadBuffer.h"
Florin Malita4aed1382017-05-25 10:38:07 -040024#include "SkShaderBase.h"
Hal Canary95e3c052017-01-11 12:44:43 -050025#include "SkUtils.h"
26#include "SkWriteBuffer.h"
rileya@google.com1c6d64b2012-07-27 15:49:05 +000027
humper@google.com05af1af2013-01-07 16:47:43 +000028static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
rileya@google.com1c6d64b2012-07-27 15:49:05 +000029 int count) {
30 if (count > 0) {
31 if (v0 == v1) {
32 sk_memset32(dst, v0, count);
33 } else {
34 int pairs = count >> 1;
35 for (int i = 0; i < pairs; i++) {
36 *dst++ = v0;
37 *dst++ = v1;
38 }
39 if (count & 1) {
40 *dst = v0;
41 }
42 }
43 }
44}
45
46// Clamp
47
humper@google.com05af1af2013-01-07 16:47:43 +000048static inline SkFixed clamp_tileproc(SkFixed x) {
rileya@google.com1c6d64b2012-07-27 15:49:05 +000049 return SkClampMax(x, 0xFFFF);
50}
51
52// Repeat
53
humper@google.com05af1af2013-01-07 16:47:43 +000054static inline SkFixed repeat_tileproc(SkFixed x) {
rileya@google.com1c6d64b2012-07-27 15:49:05 +000055 return x & 0xFFFF;
56}
57
58// Mirror
59
rileya@google.com1c6d64b2012-07-27 15:49:05 +000060static inline SkFixed mirror_tileproc(SkFixed x) {
caryclark3127c992015-12-09 12:02:30 -080061 int s = SkLeftShift(x, 15) >> 31;
rileya@google.com1c6d64b2012-07-27 15:49:05 +000062 return (x ^ s) & 0xFFFF;
63}
64
rileya@google.com1c6d64b2012-07-27 15:49:05 +000065///////////////////////////////////////////////////////////////////////////////
66
67typedef SkFixed (*TileProc)(SkFixed);
68
69///////////////////////////////////////////////////////////////////////////////
70
71static const TileProc gTileProcs[] = {
72 clamp_tileproc,
73 repeat_tileproc,
74 mirror_tileproc
75};
76
77///////////////////////////////////////////////////////////////////////////////
78
Florin Malita4aed1382017-05-25 10:38:07 -040079class SkGradientShaderBase : public SkShaderBase {
rileya@google.com1c6d64b2012-07-27 15:49:05 +000080public:
reed@google.com437d6eb2013-05-23 19:03:05 +000081 struct Descriptor {
82 Descriptor() {
83 sk_bzero(this, sizeof(*this));
84 fTileMode = SkShader::kClamp_TileMode;
85 }
skia.committer@gmail.com3e2345a2013-05-24 07:01:26 +000086
reedaddf2ed2014-08-11 08:28:24 -070087 const SkMatrix* fLocalMatrix;
brianosmane25d71c2016-09-28 11:27:28 -070088 const SkColor4f* fColors;
brianosmanb9c51372016-09-15 11:09:45 -070089 sk_sp<SkColorSpace> fColorSpace;
reed@google.com437d6eb2013-05-23 19:03:05 +000090 const SkScalar* fPos;
91 int fCount;
92 SkShader::TileMode fTileMode;
commit-bot@chromium.org6c5aea22014-04-22 16:25:15 +000093 uint32_t fGradFlags;
reed9fa60da2014-08-21 07:59:51 -070094
95 void flatten(SkWriteBuffer&) const;
96 };
97
98 class DescriptorScope : public Descriptor {
99 public:
100 DescriptorScope() {}
mtklein88fd0fb2014-12-01 06:56:38 -0800101
reed9fa60da2014-08-21 07:59:51 -0700102 bool unflatten(SkReadBuffer&);
103
104 // fColors and fPos always point into local memory, so they can be safely mutated
105 //
brianosmane25d71c2016-09-28 11:27:28 -0700106 SkColor4f* mutableColors() { return const_cast<SkColor4f*>(fColors); }
reed9fa60da2014-08-21 07:59:51 -0700107 SkScalar* mutablePos() { return const_cast<SkScalar*>(fPos); }
108
109 private:
110 enum {
111 kStorageCount = 16
112 };
brianosmane25d71c2016-09-28 11:27:28 -0700113 SkColor4f fColorStorage[kStorageCount];
reed9fa60da2014-08-21 07:59:51 -0700114 SkScalar fPosStorage[kStorageCount];
115 SkMatrix fLocalMatrixStorage;
116 SkAutoMalloc fDynamicStorage;
reed@google.com437d6eb2013-05-23 19:03:05 +0000117 };
118
mtkleincc695fe2014-12-10 10:29:19 -0800119 SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit);
Brian Salomond3b65972017-03-22 12:05:03 -0400120 ~SkGradientShaderBase() override;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000121
brianosman93110a82016-09-15 08:40:21 -0700122 // The cache is initialized on-demand when getCache32 is called.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000123 class GradientShaderCache : public SkRefCnt {
124 public:
Florin Malitacc586642017-10-24 16:18:59 -0400125 GradientShaderCache(const SkGradientShaderBase& shader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000126 ~GradientShaderCache();
127
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000128 const SkPMColor* getCache32();
129
Mike Reed6b3155c2017-04-03 14:41:44 -0400130 SkPixelRef* getCache32PixelRef() const { return fCache32PixelRef.get(); }
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000131
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000132 private:
brianosman93110a82016-09-15 08:40:21 -0700133 // Working pointer. If it's nullptr, we need to recompute the cache values.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000134 SkPMColor* fCache32;
135
Mike Reed6b3155c2017-04-03 14:41:44 -0400136 sk_sp<SkPixelRef> fCache32PixelRef;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000137 const SkGradientShaderBase& fShader;
138
brianosman93110a82016-09-15 08:40:21 -0700139 // Make sure we only initialize the cache once.
140 SkOnce fCache32InitOnce;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000141
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000142 static void initCache32(GradientShaderCache* cache);
143
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000144 static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
Florin Malitacc586642017-10-24 16:18:59 -0400145 uint32_t gradFlags);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000146 };
147
mtklein36352bf2015-03-25 18:17:31 -0700148 bool isOpaque() const override;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000149
brianosmand4546092016-09-22 12:31:58 -0700150 enum class GradientBitmapType : uint8_t {
151 kLegacy,
152 kSRGB,
153 kHalfFloat,
154 };
155
156 void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000157
158 enum {
159 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
160 /// it, use a larger cache.
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000161 kCache32Bits = 8,
reed@google.com60040292013-02-04 18:21:23 +0000162 kCache32Count = (1 << kCache32Bits),
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000163 kCache32Shift = 16 - kCache32Bits,
164 kSqrt32Shift = 8 - kCache32Bits,
165
166 /// This value is used to *read* the dither cache; it may be 0
167 /// if dithering is disabled.
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000168 kDitherStride32 = kCache32Count,
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000169 };
170
commit-bot@chromium.org6c5aea22014-04-22 16:25:15 +0000171 uint32_t getGradFlags() const { return fGradFlags; }
commit-bot@chromium.org53783b02014-04-17 21:09:49 +0000172
Florin Malita0e36b3f2017-06-05 23:33:45 -0400173 SkColor4f getXformedColor(size_t index, SkColorSpace*) const;
174
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000175protected:
Mike Kleina3771842017-05-04 19:38:48 -0400176 struct Rec {
177 SkFixed fPos; // 0...1
178 uint32_t fScale; // (1 << 24) / range
179 };
180
fmalitabc590c02016-02-22 09:12:33 -0800181 class GradientShaderBase4fContext;
182
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000183 SkGradientShaderBase(SkReadBuffer& );
mtklein36352bf2015-03-25 18:17:31 -0700184 void flatten(SkWriteBuffer&) const override;
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000185 SK_TO_STRING_OVERRIDE()
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000186
Florin Malita5f379a82017-10-18 16:22:35 -0400187 void commonAsAGradient(GradientInfo*) const;
skia.committer@gmail.comd3b28e82014-04-22 03:05:17 +0000188
mtklein36352bf2015-03-25 18:17:31 -0700189 bool onAsLuminanceColor(SkColor*) const override;
reed8367b8c2014-08-22 08:30:20 -0700190
brianosmand4546092016-09-22 12:31:58 -0700191 void initLinearBitmap(SkBitmap* bitmap) const;
192
Mike Reed1d8c42e2017-08-29 14:58:19 -0400193 bool onAppendStages(const StageRec&) const override;
Mike Kleina3771842017-05-04 19:38:48 -0400194
Florin Malita50b20842017-07-29 19:08:28 -0400195 virtual void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
196 SkRasterPipeline* postPipeline) const = 0;
Mike Kleina3771842017-05-04 19:38:48 -0400197
fmalita088e21b2016-10-05 09:28:42 -0700198 template <typename T, typename... Args>
Herb Derby83e939b2017-02-07 14:25:11 -0500199 static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
200 auto* ctx = alloc->make<T>(std::forward<Args>(args)...);
fmalita088e21b2016-10-05 09:28:42 -0700201 if (!ctx->isValid()) {
fmalita088e21b2016-10-05 09:28:42 -0700202 return nullptr;
203 }
204 return ctx;
205 }
206
Mike Kleina3771842017-05-04 19:38:48 -0400207 const SkMatrix fPtsToUnit;
208 TileMode fTileMode;
209 TileProc fTileProc;
210 uint8_t fGradFlags;
211 Rec* fRecs;
212
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000213private:
214 enum {
215 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
216
brianosmanb9c51372016-09-15 11:09:45 -0700217 kStorageSize = kColorStorageCount *
218 (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec) + sizeof(SkColor4f))
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000219 };
brianosmanb9c51372016-09-15 11:09:45 -0700220 SkColor fStorage[(kStorageSize + 3) >> 2];
reedf3182eb2015-11-17 08:12:19 -0800221public:
brianosmanb9c51372016-09-15 11:09:45 -0700222 SkColor* fOrigColors; // original colors, before modulation by paint in context.
223 SkColor4f* fOrigColors4f; // original colors, as linear floats
224 SkScalar* fOrigPos; // original positions
225 int fColorCount;
226 sk_sp<SkColorSpace> fColorSpace; // color space of gradient stops
reedf3182eb2015-11-17 08:12:19 -0800227
228 bool colorsAreOpaque() const { return fColorsAreOpaque; }
229
fmenozzicd9a1d02016-08-15 07:03:47 -0700230 TileMode getTileMode() const { return fTileMode; }
231 Rec* getRecs() const { return fRecs; }
232
reedf3182eb2015-11-17 08:12:19 -0800233private:
brianosmanb9c51372016-09-15 11:09:45 -0700234 bool fColorsAreOpaque;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000235
Florin Malitacc586642017-10-24 16:18:59 -0400236 sk_sp<GradientShaderCache> refCache() const;
Hal Canary67b39de2016-11-07 11:47:44 -0500237 mutable SkMutex fCacheMutex;
238 mutable sk_sp<GradientShaderCache> fCache;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000239
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000240 void initCommon();
241
Florin Malita4aed1382017-05-25 10:38:07 -0400242 typedef SkShaderBase INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000243};
244
Mike Kleina3771842017-05-04 19:38:48 -0400245
reed@google.com55853db2013-02-01 19:34:59 +0000246static inline int init_dither_toggle(int x, int y) {
reed@google.com60040292013-02-04 18:21:23 +0000247 x &= 1;
248 y = (y & 1) << 1;
249 return (x | y) * SkGradientShaderBase::kDitherStride32;
reed@google.com55853db2013-02-01 19:34:59 +0000250}
251
252static inline int next_dither_toggle(int toggle) {
253 return toggle ^ SkGradientShaderBase::kDitherStride32;
254}
255
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000256///////////////////////////////////////////////////////////////////////////////
257
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000258#if SK_SUPPORT_GPU
259
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400260#include "GrColorSpaceInfo.h"
bsalomon@google.com77af6802013-10-02 13:04:56 +0000261#include "GrCoordTransform.h"
bsalomon6251d172014-10-15 10:50:36 -0700262#include "GrFragmentProcessor.h"
egdaniel64c47282015-11-13 06:54:19 -0800263#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel018fb622015-10-28 07:26:40 -0700264#include "glsl/GrGLSLProgramDataManager.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000265
egdaniel605dd0f2014-11-12 08:35:25 -0800266class GrInvariantOutput;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000267
268/*
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000269 * The interpretation of the texture matrix depends on the sample mode. The
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000270 * texture matrix is applied both when the texture coordinates are explicit
271 * and when vertex positions are used as texture coordinates. In the latter
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000272 * case the texture matrix is applied to the pre-view-matrix position
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000273 * values.
274 *
275 * Normal SampleMode
276 * The post-matrix texture coordinates are in normalize space with (0,0) at
277 * the top-left and (1,1) at the bottom right.
278 * RadialGradient
279 * The matrix specifies the radial gradient parameters.
280 * (0,0) in the post-matrix space is center of the radial gradient.
281 * Radial2Gradient
282 * Matrix transforms to space where first circle is centered at the
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000283 * origin. The second circle will be centered (x, 0) where x may be
284 * 0 and is provided by setRadial2Params. The post-matrix space is
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000285 * normalized such that 1 is the second radius - first radius.
286 * SweepGradient
287 * The angle from the origin of texture coordinates in post-matrix space
288 * determines the gradient value.
289 */
290
rileya@google.comb3e50f22012-08-20 17:43:08 +0000291 class GrTextureStripAtlas;
292
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000293// Base class for Gr gradient effects
joshualittb0a8a372014-09-23 09:50:21 -0700294class GrGradientEffect : public GrFragmentProcessor {
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000295public:
brianosman9557c272016-09-15 06:59:15 -0700296 struct CreateArgs {
297 CreateArgs(GrContext* context,
298 const SkGradientShaderBase* shader,
299 const SkMatrix* matrix,
brianosmanb9c51372016-09-15 11:09:45 -0700300 SkShader::TileMode tileMode,
Brian Osman5911a7c2017-10-25 12:52:31 -0400301 const SkColorSpace* dstColorSpace)
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400302 : fContext(context)
303 , fShader(shader)
304 , fMatrix(matrix)
Brian Osman5911a7c2017-10-25 12:52:31 -0400305 , fDstColorSpace(dstColorSpace) {
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400306 switch (tileMode) {
307 case SkShader::kClamp_TileMode:
308 fWrapMode = GrSamplerState::WrapMode::kClamp;
309 break;
310 case SkShader::kRepeat_TileMode:
311 fWrapMode = GrSamplerState::WrapMode::kRepeat;
312 break;
313 case SkShader::kMirror_TileMode:
314 fWrapMode = GrSamplerState::WrapMode::kMirrorRepeat;
315 break;
316 }
317 }
318
319 CreateArgs(GrContext* context,
320 const SkGradientShaderBase* shader,
321 const SkMatrix* matrix,
322 GrSamplerState::WrapMode wrapMode,
Brian Osman5911a7c2017-10-25 12:52:31 -0400323 const SkColorSpace* dstColorSpace)
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400324 : fContext(context)
325 , fShader(shader)
326 , fMatrix(matrix)
327 , fWrapMode(wrapMode)
Brian Osman5911a7c2017-10-25 12:52:31 -0400328 , fDstColorSpace(dstColorSpace) {}
brianosman9557c272016-09-15 06:59:15 -0700329
330 GrContext* fContext;
331 const SkGradientShaderBase* fShader;
332 const SkMatrix* fMatrix;
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400333 GrSamplerState::WrapMode fWrapMode;
Brian Osman5911a7c2017-10-25 12:52:31 -0400334 const SkColorSpace* fDstColorSpace;
brianosman9557c272016-09-15 06:59:15 -0700335 };
336
fmenozzi55d318d2016-08-09 08:05:57 -0700337 class GLSLProcessor;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000338
Brian Salomond3b65972017-03-22 12:05:03 -0400339 ~GrGradientEffect() override;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000340
rileya@google.comb3e50f22012-08-20 17:43:08 +0000341 bool useAtlas() const { return SkToBool(-1 != fRow); }
fmenozzicd9a1d02016-08-15 07:03:47 -0700342 SkScalar getYCoord() const { return fYCoord; }
rileya@google.comb3e50f22012-08-20 17:43:08 +0000343
fmenozzicd9a1d02016-08-15 07:03:47 -0700344 enum ColorType {
345 kTwo_ColorType,
Brian Osmana8e57442017-09-11 17:21:35 -0400346 kThree_ColorType, // 0, t, 1
fmenozzicd9a1d02016-08-15 07:03:47 -0700347 kTexture_ColorType,
Brian Salomon466ad992016-10-13 16:08:36 -0400348 kSingleHardStop_ColorType, // 0, t, t, 1
fmenozzicd9a1d02016-08-15 07:03:47 -0700349 kHardStopLeftEdged_ColorType, // 0, 0, 1
350 kHardStopRightEdged_ColorType, // 0, 1, 1
fmenozzicd9a1d02016-08-15 07:03:47 -0700351 };
352
353 ColorType getColorType() const { return fColorType; }
354
355 // Determines the type of gradient, one of:
356 // - Two-color
357 // - Symmetric three-color
358 // - Texture
359 // - Centered hard stop
360 // - Left-edged hard stop
361 // - Right-edged hard stop
362 ColorType determineColorType(const SkGradientShaderBase& shader);
bsalomon@google.com82d12232013-09-09 15:36:26 +0000363
364 enum PremulType {
365 kBeforeInterp_PremulType,
366 kAfterInterp_PremulType,
367 };
368
369 PremulType getPremulType() const { return fPremulType; }
370
Brian Osmand43f7b62017-10-19 15:42:01 -0400371 const GrColor4f* getColors4f(int pos) const {
brianosmanb9c51372016-09-15 11:09:45 -0700372 SkASSERT(fColorType != kTexture_ColorType);
373 SkASSERT(pos < fColors4f.count());
374 return &fColors4f[pos];
375 }
376
bsalomon@google.comd4726202012-08-03 14:34:46 +0000377protected:
Ethan Nicholasabff9562017-10-09 10:54:08 -0400378 GrGradientEffect(ClassID classID, const CreateArgs&, bool isOpaque);
Brian Salomonf8480b92017-07-27 15:45:59 -0400379 explicit GrGradientEffect(const GrGradientEffect&); // facilitates clone() implementations
Brian Salomon587e08f2017-01-27 10:59:27 -0500380
Brian Osman5911a7c2017-10-25 12:52:31 -0400381 // Helper function used by derived class factories to handle color space transformation and
382 // modulation by input alpha.
383 static std::unique_ptr<GrFragmentProcessor> AdjustFP(
384 std::unique_ptr<GrGradientEffect> gradientFP, const CreateArgs& args) {
385 if (!gradientFP->isValid()) {
386 return nullptr;
387 }
388 std::unique_ptr<GrFragmentProcessor> fp;
389 // With analytic gradients, we pre-convert the stops to the destination color space, so no
390 // xform is needed. With texture-based gradients, we leave the data in the source color
391 // space (to avoid clamping if we can't use F16)... Add an extra FP to do the xform.
392 if (kTexture_ColorType == gradientFP->getColorType()) {
393 fp = GrColorSpaceXformEffect::Make(std::move(gradientFP),
394 args.fShader->fColorSpace.get(),
395 args.fDstColorSpace);
396 } else {
397 fp = std::move(gradientFP);
398 }
399 return GrFragmentProcessor::MulOutputByInputAlpha(std::move(fp));
400 }
401
402#if GR_TEST_UTILS
Brian Osmane75c19f2016-10-10 11:26:43 -0400403 /** Helper struct that stores (and populates) parameters to construct a random gradient.
Brian Osmana2196532016-10-17 12:48:13 -0400404 If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and
405 fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount
406 will be the number of color stops in either case, and fColors and fStops can be passed to
407 the gradient factory. (The constructor may decide not to use stops, in which case fStops
408 will be nullptr). */
Brian Osman3f748602016-10-03 18:29:03 -0400409 struct RandomGradientParams {
Brian Salomon5d4cd9e2017-02-09 11:16:46 -0500410 static const int kMaxRandomGradientColors = 5;
Brian Osmane75c19f2016-10-10 11:26:43 -0400411
Brian Osman3f748602016-10-03 18:29:03 -0400412 RandomGradientParams(SkRandom* r);
413
Brian Osmana2196532016-10-17 12:48:13 -0400414 bool fUseColors4f;
Brian Osman3f748602016-10-03 18:29:03 -0400415 SkColor fColors[kMaxRandomGradientColors];
Brian Osmana2196532016-10-17 12:48:13 -0400416 SkColor4f fColors4f[kMaxRandomGradientColors];
417 sk_sp<SkColorSpace> fColorSpace;
Brian Osman3f748602016-10-03 18:29:03 -0400418 SkScalar fStopStorage[kMaxRandomGradientColors];
419 SkShader::TileMode fTileMode;
420 int fColorCount;
421 SkScalar* fStops;
422 };
Hal Canary6f6961e2017-01-31 13:50:44 -0500423 #endif
bsalomon@google.comd4726202012-08-03 14:34:46 +0000424
mtklein36352bf2015-03-25 18:17:31 -0700425 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000426
commit-bot@chromium.org5fd7d5c2013-10-04 01:20:09 +0000427 const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
428
Brian Salomon6af27012017-06-09 08:21:42 -0400429 /** Checks whether the constructor failed to fully initialize the processor. */
Brian Salomon06e547c2017-06-09 16:11:32 -0400430 bool isValid() const {
431 return fColorType != kTexture_ColorType || fTextureSampler.isInitialized();
432 }
Brian Salomon6af27012017-06-09 08:21:42 -0400433
bsalomon@google.comd4726202012-08-03 14:34:46 +0000434private:
Brian Salomon587e08f2017-01-27 10:59:27 -0500435 static OptimizationFlags OptFlags(bool isOpaque);
436
Brian Osmand43f7b62017-10-19 15:42:01 -0400437 SkTDArray<GrColor4f> fColors4f;
brianosmanb9c51372016-09-15 11:09:45 -0700438
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400439 SkTDArray<SkScalar> fPositions;
440 GrSamplerState::WrapMode fWrapMode;
fmenozzicd9a1d02016-08-15 07:03:47 -0700441
bsalomon@google.com77af6802013-10-02 13:04:56 +0000442 GrCoordTransform fCoordTransform;
Brian Salomon0bbecb22016-11-17 11:38:22 -0500443 TextureSampler fTextureSampler;
bsalomon@google.com81712882012-11-01 17:12:34 +0000444 SkScalar fYCoord;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000445 GrTextureStripAtlas* fAtlas;
446 int fRow;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000447 bool fIsOpaque;
fmenozzicd9a1d02016-08-15 07:03:47 -0700448 ColorType fColorType;
449 PremulType fPremulType; // This is already baked into the table for texture gradients, and
450 // only changes behavior for gradients that don't use a texture.
joshualittb0a8a372014-09-23 09:50:21 -0700451 typedef GrFragmentProcessor INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000452
453};
454
455///////////////////////////////////////////////////////////////////////////////
456
fmenozzicd9a1d02016-08-15 07:03:47 -0700457// Base class for GL gradient effects
fmenozzi55d318d2016-08-09 08:05:57 -0700458class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000459public:
fmenozzicd9a1d02016-08-15 07:03:47 -0700460 GLSLProcessor() {
461 fCachedYCoord = SK_ScalarMax;
462 }
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000463
wangyixb1daa862015-08-18 11:29:31 -0700464protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400465 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000466
bsalomon@google.comf78df332012-10-29 12:43:38 +0000467protected:
bsalomon63e99f72014-07-21 08:03:14 -0700468 /**
469 * Subclasses must call this. It will return a key for the part of the shader code controlled
470 * by the base class. The subclasses must stick it in their key and then pass it to the below
471 * emit* functions from their emitCode function.
472 */
joshualittb0a8a372014-09-23 09:50:21 -0700473 static uint32_t GenBaseGradientKey(const GrProcessor&);
bsalomon63e99f72014-07-21 08:03:14 -0700474
475 // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
476 // should call this method from their emitCode().
egdaniel7ea439b2015-12-03 09:20:44 -0800477 void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
bsalomon63e99f72014-07-21 08:03:14 -0700478
fmenozzicd9a1d02016-08-15 07:03:47 -0700479 // Emit code that gets a fragment's color from an expression for t; has branches for
480 // several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+
481 // color gradients that use the traditional texture lookup, as well as several varieties
482 // of hard stop gradients
cdalton85285412016-02-18 12:37:07 -0800483 void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel7ea439b2015-12-03 09:20:44 -0800484 GrGLSLUniformHandler* uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500485 const GrShaderCaps* shaderCaps,
joshualitt60030bc2014-11-25 14:21:55 -0800486 const GrGradientEffect&,
bsalomon63e99f72014-07-21 08:03:14 -0700487 const char* gradientTValue,
bsalomon63e99f72014-07-21 08:03:14 -0700488 const char* outputColor,
489 const char* inputColor,
bsalomonb58a2b42016-09-26 06:55:02 -0700490 const TextureSamplers&);
bsalomon63e99f72014-07-21 08:03:14 -0700491
492private:
Florin Malitab81a8b92017-08-08 12:14:17 -0400493 void emitAnalyticalColor(GrGLSLFPFragmentBuilder* fragBuilder,
494 GrGLSLUniformHandler* uniformHandler,
495 const GrShaderCaps* shaderCaps,
496 const GrGradientEffect&,
497 const char* gradientTValue,
498 const char* outputColor,
499 const char* inputColor);
500
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000501 enum {
Brian Osmanfe3e8582017-10-20 11:27:49 -0400502 // First bit for premul before/after interpolation
fmenozzicd9a1d02016-08-15 07:03:47 -0700503 kPremulBeforeInterpKey = 1,
bsalomon@google.com82d12232013-09-09 15:36:26 +0000504
fmenozzicd9a1d02016-08-15 07:03:47 -0700505 // Next three bits for 2/3 color type or different special
Brian Osmanfe3e8582017-10-20 11:27:49 -0400506 // hard stop cases ('none' means using texture atlas)
fmenozzicd9a1d02016-08-15 07:03:47 -0700507 kTwoColorKey = 2,
508 kThreeColorKey = 4,
Brian Salomonf8480b92017-07-27 15:45:59 -0400509
Brian Osman2ab4b2b2017-09-12 11:20:56 -0400510 kHardStopCenteredKey = 6,
511 kHardStopZeroZeroOneKey = 8,
512 kHardStopZeroOneOneKey = 10,
fmenozzicd9a1d02016-08-15 07:03:47 -0700513
514 // Next two bits for tile mode
515 kClampTileMode = 16,
516 kRepeatTileMode = 32,
517 kMirrorTileMode = 48,
518
519 // Lower six bits for premul, 2/3 color type, and tile mode
520 kReservedBits = 6,
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000521 };
522
bsalomon@google.com81712882012-11-01 17:12:34 +0000523 SkScalar fCachedYCoord;
fmenozzicd9a1d02016-08-15 07:03:47 -0700524 GrGLSLProgramDataManager::UniformHandle fColorsUni;
Brian Osmana8e57442017-09-11 17:21:35 -0400525 GrGLSLProgramDataManager::UniformHandle fExtraStopT;
egdaniel018fb622015-10-28 07:26:40 -0700526 GrGLSLProgramDataManager::UniformHandle fFSYUni;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000527
egdaniel64c47282015-11-13 06:54:19 -0800528 typedef GrGLSLFragmentProcessor INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000529};
530
531#endif
532
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000533#endif