blob: 23ff30f9d4f47822248ae71e8328971cc0819111 [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:
fmalita37d86882015-10-09 10:22:46 -0700125 GradientShaderCache(U8CPU alpha, bool dither, 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
132 unsigned getAlpha() const { return fCacheAlpha; }
fmalita37d86882015-10-09 10:22:46 -0700133 bool getDither() const { return fCacheDither; }
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000134
135 private:
brianosman93110a82016-09-15 08:40:21 -0700136 // Working pointer. If it's nullptr, we need to recompute the cache values.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000137 SkPMColor* fCache32;
138
Mike Reed6b3155c2017-04-03 14:41:44 -0400139 sk_sp<SkPixelRef> fCache32PixelRef;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000140 const unsigned fCacheAlpha; // The alpha value we used when we computed the cache.
141 // Larger than 8bits so we can store uninitialized
142 // value.
fmalita37d86882015-10-09 10:22:46 -0700143 const bool fCacheDither; // The dither flag used when we computed the cache.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000144
145 const SkGradientShaderBase& fShader;
146
brianosman93110a82016-09-15 08:40:21 -0700147 // Make sure we only initialize the cache once.
148 SkOnce fCache32InitOnce;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000149
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000150 static void initCache32(GradientShaderCache* cache);
151
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000152 static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
fmalita37d86882015-10-09 10:22:46 -0700153 U8CPU alpha, uint32_t gradFlags, bool dither);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000154 };
155
Florin Malita4aed1382017-05-25 10:38:07 -0400156 class GradientShaderBaseContext : public Context {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000157 public:
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000158 GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000159
mtklein36352bf2015-03-25 18:17:31 -0700160 uint32_t getFlags() const override { return fFlags; }
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000161
fmalita088e21b2016-10-05 09:28:42 -0700162 bool isValid() const;
163
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000164 protected:
165 SkMatrix fDstToIndex;
Cary Clark9480d822017-10-19 18:01:13 -0400166 SkMatrixPriv::MapXYProc fDstToIndexProc;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000167 uint8_t fDstToIndexClass;
168 uint8_t fFlags;
fmalita37d86882015-10-09 10:22:46 -0700169 bool fDither;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000170
Hal Canary67b39de2016-11-07 11:47:44 -0500171 sk_sp<GradientShaderCache> fCache;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000172
173 private:
Florin Malita4aed1382017-05-25 10:38:07 -0400174 typedef Context INHERITED;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000175 };
176
mtklein36352bf2015-03-25 18:17:31 -0700177 bool isOpaque() const override;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000178
brianosmand4546092016-09-22 12:31:58 -0700179 enum class GradientBitmapType : uint8_t {
180 kLegacy,
181 kSRGB,
182 kHalfFloat,
183 };
184
185 void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000186
187 enum {
188 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
189 /// it, use a larger cache.
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000190 kCache32Bits = 8,
reed@google.com60040292013-02-04 18:21:23 +0000191 kCache32Count = (1 << kCache32Bits),
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000192 kCache32Shift = 16 - kCache32Bits,
193 kSqrt32Shift = 8 - kCache32Bits,
194
195 /// This value is used to *read* the dither cache; it may be 0
196 /// if dithering is disabled.
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000197 kDitherStride32 = kCache32Count,
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000198 };
199
commit-bot@chromium.org6c5aea22014-04-22 16:25:15 +0000200 uint32_t getGradFlags() const { return fGradFlags; }
commit-bot@chromium.org53783b02014-04-17 21:09:49 +0000201
Florin Malita0e36b3f2017-06-05 23:33:45 -0400202 SkColor4f getXformedColor(size_t index, SkColorSpace*) const;
203
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000204protected:
Mike Kleina3771842017-05-04 19:38:48 -0400205 struct Rec {
206 SkFixed fPos; // 0...1
207 uint32_t fScale; // (1 << 24) / range
208 };
209
fmalitabc590c02016-02-22 09:12:33 -0800210 class GradientShaderBase4fContext;
211
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000212 SkGradientShaderBase(SkReadBuffer& );
mtklein36352bf2015-03-25 18:17:31 -0700213 void flatten(SkWriteBuffer&) const override;
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000214 SK_TO_STRING_OVERRIDE()
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000215
Florin Malita5f379a82017-10-18 16:22:35 -0400216 void commonAsAGradient(GradientInfo*) const;
skia.committer@gmail.comd3b28e82014-04-22 03:05:17 +0000217
mtklein36352bf2015-03-25 18:17:31 -0700218 bool onAsLuminanceColor(SkColor*) const override;
reed8367b8c2014-08-22 08:30:20 -0700219
brianosmand4546092016-09-22 12:31:58 -0700220 void initLinearBitmap(SkBitmap* bitmap) const;
221
Mike Reed1d8c42e2017-08-29 14:58:19 -0400222 bool onAppendStages(const StageRec&) const override;
Mike Kleina3771842017-05-04 19:38:48 -0400223
Florin Malita50b20842017-07-29 19:08:28 -0400224 virtual void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
225 SkRasterPipeline* postPipeline) const = 0;
Mike Kleina3771842017-05-04 19:38:48 -0400226
fmalita088e21b2016-10-05 09:28:42 -0700227 template <typename T, typename... Args>
Herb Derby83e939b2017-02-07 14:25:11 -0500228 static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
229 auto* ctx = alloc->make<T>(std::forward<Args>(args)...);
fmalita088e21b2016-10-05 09:28:42 -0700230 if (!ctx->isValid()) {
fmalita088e21b2016-10-05 09:28:42 -0700231 return nullptr;
232 }
233 return ctx;
234 }
235
Mike Kleina3771842017-05-04 19:38:48 -0400236 const SkMatrix fPtsToUnit;
237 TileMode fTileMode;
238 TileProc fTileProc;
239 uint8_t fGradFlags;
240 Rec* fRecs;
241
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000242private:
243 enum {
244 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
245
brianosmanb9c51372016-09-15 11:09:45 -0700246 kStorageSize = kColorStorageCount *
247 (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec) + sizeof(SkColor4f))
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000248 };
brianosmanb9c51372016-09-15 11:09:45 -0700249 SkColor fStorage[(kStorageSize + 3) >> 2];
reedf3182eb2015-11-17 08:12:19 -0800250public:
brianosmanb9c51372016-09-15 11:09:45 -0700251 SkColor* fOrigColors; // original colors, before modulation by paint in context.
252 SkColor4f* fOrigColors4f; // original colors, as linear floats
253 SkScalar* fOrigPos; // original positions
254 int fColorCount;
255 sk_sp<SkColorSpace> fColorSpace; // color space of gradient stops
reedf3182eb2015-11-17 08:12:19 -0800256
257 bool colorsAreOpaque() const { return fColorsAreOpaque; }
258
fmenozzicd9a1d02016-08-15 07:03:47 -0700259 TileMode getTileMode() const { return fTileMode; }
260 Rec* getRecs() const { return fRecs; }
261
reedf3182eb2015-11-17 08:12:19 -0800262private:
brianosmanb9c51372016-09-15 11:09:45 -0700263 bool fColorsAreOpaque;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000264
Hal Canary67b39de2016-11-07 11:47:44 -0500265 sk_sp<GradientShaderCache> refCache(U8CPU alpha, bool dither) const;
266 mutable SkMutex fCacheMutex;
267 mutable sk_sp<GradientShaderCache> fCache;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000268
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000269 void initCommon();
270
Florin Malita4aed1382017-05-25 10:38:07 -0400271 typedef SkShaderBase INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000272};
273
Mike Kleina3771842017-05-04 19:38:48 -0400274
reed@google.com55853db2013-02-01 19:34:59 +0000275static inline int init_dither_toggle(int x, int y) {
reed@google.com60040292013-02-04 18:21:23 +0000276 x &= 1;
277 y = (y & 1) << 1;
278 return (x | y) * SkGradientShaderBase::kDitherStride32;
reed@google.com55853db2013-02-01 19:34:59 +0000279}
280
281static inline int next_dither_toggle(int toggle) {
282 return toggle ^ SkGradientShaderBase::kDitherStride32;
283}
284
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000285///////////////////////////////////////////////////////////////////////////////
286
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000287#if SK_SUPPORT_GPU
288
brianosmanb9c51372016-09-15 11:09:45 -0700289#include "GrColorSpaceXform.h"
bsalomon@google.com77af6802013-10-02 13:04:56 +0000290#include "GrCoordTransform.h"
bsalomon6251d172014-10-15 10:50:36 -0700291#include "GrFragmentProcessor.h"
Brian Osmanc624d9d2017-03-08 11:42:02 -0500292#include "glsl/GrGLSLColorSpaceXformHelper.h"
egdaniel64c47282015-11-13 06:54:19 -0800293#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel018fb622015-10-28 07:26:40 -0700294#include "glsl/GrGLSLProgramDataManager.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000295
egdaniel605dd0f2014-11-12 08:35:25 -0800296class GrInvariantOutput;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000297
298/*
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000299 * The interpretation of the texture matrix depends on the sample mode. The
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000300 * texture matrix is applied both when the texture coordinates are explicit
301 * and when vertex positions are used as texture coordinates. In the latter
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000302 * case the texture matrix is applied to the pre-view-matrix position
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000303 * values.
304 *
305 * Normal SampleMode
306 * The post-matrix texture coordinates are in normalize space with (0,0) at
307 * the top-left and (1,1) at the bottom right.
308 * RadialGradient
309 * The matrix specifies the radial gradient parameters.
310 * (0,0) in the post-matrix space is center of the radial gradient.
311 * Radial2Gradient
312 * Matrix transforms to space where first circle is centered at the
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000313 * origin. The second circle will be centered (x, 0) where x may be
314 * 0 and is provided by setRadial2Params. The post-matrix space is
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000315 * normalized such that 1 is the second radius - first radius.
316 * SweepGradient
317 * The angle from the origin of texture coordinates in post-matrix space
318 * determines the gradient value.
319 */
320
rileya@google.comb3e50f22012-08-20 17:43:08 +0000321 class GrTextureStripAtlas;
322
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000323// Base class for Gr gradient effects
joshualittb0a8a372014-09-23 09:50:21 -0700324class GrGradientEffect : public GrFragmentProcessor {
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000325public:
brianosman9557c272016-09-15 06:59:15 -0700326 struct CreateArgs {
327 CreateArgs(GrContext* context,
328 const SkGradientShaderBase* shader,
329 const SkMatrix* matrix,
brianosmanb9c51372016-09-15 11:09:45 -0700330 SkShader::TileMode tileMode,
331 sk_sp<GrColorSpaceXform> colorSpaceXform,
332 bool gammaCorrect)
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400333 : fContext(context)
334 , fShader(shader)
335 , fMatrix(matrix)
336 , fColorSpaceXform(std::move(colorSpaceXform))
337 , fGammaCorrect(gammaCorrect) {
338 switch (tileMode) {
339 case SkShader::kClamp_TileMode:
340 fWrapMode = GrSamplerState::WrapMode::kClamp;
341 break;
342 case SkShader::kRepeat_TileMode:
343 fWrapMode = GrSamplerState::WrapMode::kRepeat;
344 break;
345 case SkShader::kMirror_TileMode:
346 fWrapMode = GrSamplerState::WrapMode::kMirrorRepeat;
347 break;
348 }
349 }
350
351 CreateArgs(GrContext* context,
352 const SkGradientShaderBase* shader,
353 const SkMatrix* matrix,
354 GrSamplerState::WrapMode wrapMode,
355 sk_sp<GrColorSpaceXform> colorSpaceXform,
356 bool gammaCorrect)
357 : fContext(context)
358 , fShader(shader)
359 , fMatrix(matrix)
360 , fWrapMode(wrapMode)
361 , fColorSpaceXform(std::move(colorSpaceXform))
362 , fGammaCorrect(gammaCorrect) {}
brianosman9557c272016-09-15 06:59:15 -0700363
364 GrContext* fContext;
365 const SkGradientShaderBase* fShader;
366 const SkMatrix* fMatrix;
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400367 GrSamplerState::WrapMode fWrapMode;
brianosmanb9c51372016-09-15 11:09:45 -0700368 sk_sp<GrColorSpaceXform> fColorSpaceXform;
369 bool fGammaCorrect;
brianosman9557c272016-09-15 06:59:15 -0700370 };
371
fmenozzi55d318d2016-08-09 08:05:57 -0700372 class GLSLProcessor;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000373
Brian Salomond3b65972017-03-22 12:05:03 -0400374 ~GrGradientEffect() override;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000375
rileya@google.comb3e50f22012-08-20 17:43:08 +0000376 bool useAtlas() const { return SkToBool(-1 != fRow); }
fmenozzicd9a1d02016-08-15 07:03:47 -0700377 SkScalar getYCoord() const { return fYCoord; }
rileya@google.comb3e50f22012-08-20 17:43:08 +0000378
fmenozzicd9a1d02016-08-15 07:03:47 -0700379 enum ColorType {
380 kTwo_ColorType,
Brian Osmana8e57442017-09-11 17:21:35 -0400381 kThree_ColorType, // 0, t, 1
fmenozzicd9a1d02016-08-15 07:03:47 -0700382 kTexture_ColorType,
Brian Salomon466ad992016-10-13 16:08:36 -0400383 kSingleHardStop_ColorType, // 0, t, t, 1
fmenozzicd9a1d02016-08-15 07:03:47 -0700384 kHardStopLeftEdged_ColorType, // 0, 0, 1
385 kHardStopRightEdged_ColorType, // 0, 1, 1
fmenozzicd9a1d02016-08-15 07:03:47 -0700386 };
387
388 ColorType getColorType() const { return fColorType; }
389
390 // Determines the type of gradient, one of:
391 // - Two-color
392 // - Symmetric three-color
393 // - Texture
394 // - Centered hard stop
395 // - Left-edged hard stop
396 // - Right-edged hard stop
397 ColorType determineColorType(const SkGradientShaderBase& shader);
bsalomon@google.com82d12232013-09-09 15:36:26 +0000398
399 enum PremulType {
400 kBeforeInterp_PremulType,
401 kAfterInterp_PremulType,
402 };
403
404 PremulType getPremulType() const { return fPremulType; }
405
Brian Osmand43f7b62017-10-19 15:42:01 -0400406 const GrColor4f* getColors4f(int pos) const {
brianosmanb9c51372016-09-15 11:09:45 -0700407 SkASSERT(fColorType != kTexture_ColorType);
408 SkASSERT(pos < fColors4f.count());
409 return &fColors4f[pos];
410 }
411
bsalomon@google.comd4726202012-08-03 14:34:46 +0000412protected:
Ethan Nicholasabff9562017-10-09 10:54:08 -0400413 GrGradientEffect(ClassID classID, const CreateArgs&, bool isOpaque);
Brian Salomonf8480b92017-07-27 15:45:59 -0400414 explicit GrGradientEffect(const GrGradientEffect&); // facilitates clone() implementations
Brian Salomon587e08f2017-01-27 10:59:27 -0500415
Hal Canary6f6961e2017-01-31 13:50:44 -0500416 #if GR_TEST_UTILS
Brian Osmane75c19f2016-10-10 11:26:43 -0400417 /** Helper struct that stores (and populates) parameters to construct a random gradient.
Brian Osmana2196532016-10-17 12:48:13 -0400418 If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and
419 fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount
420 will be the number of color stops in either case, and fColors and fStops can be passed to
421 the gradient factory. (The constructor may decide not to use stops, in which case fStops
422 will be nullptr). */
Brian Osman3f748602016-10-03 18:29:03 -0400423 struct RandomGradientParams {
Brian Salomon5d4cd9e2017-02-09 11:16:46 -0500424 static const int kMaxRandomGradientColors = 5;
Brian Osmane75c19f2016-10-10 11:26:43 -0400425
Brian Osman3f748602016-10-03 18:29:03 -0400426 RandomGradientParams(SkRandom* r);
427
Brian Osmana2196532016-10-17 12:48:13 -0400428 bool fUseColors4f;
Brian Osman3f748602016-10-03 18:29:03 -0400429 SkColor fColors[kMaxRandomGradientColors];
Brian Osmana2196532016-10-17 12:48:13 -0400430 SkColor4f fColors4f[kMaxRandomGradientColors];
431 sk_sp<SkColorSpace> fColorSpace;
Brian Osman3f748602016-10-03 18:29:03 -0400432 SkScalar fStopStorage[kMaxRandomGradientColors];
433 SkShader::TileMode fTileMode;
434 int fColorCount;
435 SkScalar* fStops;
436 };
Hal Canary6f6961e2017-01-31 13:50:44 -0500437 #endif
bsalomon@google.comd4726202012-08-03 14:34:46 +0000438
mtklein36352bf2015-03-25 18:17:31 -0700439 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000440
commit-bot@chromium.org5fd7d5c2013-10-04 01:20:09 +0000441 const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
442
Brian Salomon6af27012017-06-09 08:21:42 -0400443 /** Checks whether the constructor failed to fully initialize the processor. */
Brian Salomon06e547c2017-06-09 16:11:32 -0400444 bool isValid() const {
445 return fColorType != kTexture_ColorType || fTextureSampler.isInitialized();
446 }
Brian Salomon6af27012017-06-09 08:21:42 -0400447
bsalomon@google.comd4726202012-08-03 14:34:46 +0000448private:
Brian Salomon587e08f2017-01-27 10:59:27 -0500449 static OptimizationFlags OptFlags(bool isOpaque);
450
Brian Osmand43f7b62017-10-19 15:42:01 -0400451 SkTDArray<GrColor4f> fColors4f;
brianosmanb9c51372016-09-15 11:09:45 -0700452
Brian Osmand43f7b62017-10-19 15:42:01 -0400453 // Only present if a color space transformation is needed
brianosmanb9c51372016-09-15 11:09:45 -0700454 sk_sp<GrColorSpaceXform> fColorSpaceXform;
455
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400456 SkTDArray<SkScalar> fPositions;
457 GrSamplerState::WrapMode fWrapMode;
fmenozzicd9a1d02016-08-15 07:03:47 -0700458
bsalomon@google.com77af6802013-10-02 13:04:56 +0000459 GrCoordTransform fCoordTransform;
Brian Salomon0bbecb22016-11-17 11:38:22 -0500460 TextureSampler fTextureSampler;
bsalomon@google.com81712882012-11-01 17:12:34 +0000461 SkScalar fYCoord;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000462 GrTextureStripAtlas* fAtlas;
463 int fRow;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000464 bool fIsOpaque;
fmenozzicd9a1d02016-08-15 07:03:47 -0700465 ColorType fColorType;
466 PremulType fPremulType; // This is already baked into the table for texture gradients, and
467 // only changes behavior for gradients that don't use a texture.
joshualittb0a8a372014-09-23 09:50:21 -0700468 typedef GrFragmentProcessor INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000469
470};
471
472///////////////////////////////////////////////////////////////////////////////
473
fmenozzicd9a1d02016-08-15 07:03:47 -0700474// Base class for GL gradient effects
fmenozzi55d318d2016-08-09 08:05:57 -0700475class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000476public:
fmenozzicd9a1d02016-08-15 07:03:47 -0700477 GLSLProcessor() {
478 fCachedYCoord = SK_ScalarMax;
479 }
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000480
wangyixb1daa862015-08-18 11:29:31 -0700481protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400482 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000483
bsalomon@google.comf78df332012-10-29 12:43:38 +0000484protected:
bsalomon63e99f72014-07-21 08:03:14 -0700485 /**
486 * Subclasses must call this. It will return a key for the part of the shader code controlled
487 * by the base class. The subclasses must stick it in their key and then pass it to the below
488 * emit* functions from their emitCode function.
489 */
joshualittb0a8a372014-09-23 09:50:21 -0700490 static uint32_t GenBaseGradientKey(const GrProcessor&);
bsalomon63e99f72014-07-21 08:03:14 -0700491
492 // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
493 // should call this method from their emitCode().
egdaniel7ea439b2015-12-03 09:20:44 -0800494 void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
bsalomon63e99f72014-07-21 08:03:14 -0700495
fmenozzicd9a1d02016-08-15 07:03:47 -0700496 // Emit code that gets a fragment's color from an expression for t; has branches for
497 // several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+
498 // color gradients that use the traditional texture lookup, as well as several varieties
499 // of hard stop gradients
cdalton85285412016-02-18 12:37:07 -0800500 void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel7ea439b2015-12-03 09:20:44 -0800501 GrGLSLUniformHandler* uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500502 const GrShaderCaps* shaderCaps,
joshualitt60030bc2014-11-25 14:21:55 -0800503 const GrGradientEffect&,
bsalomon63e99f72014-07-21 08:03:14 -0700504 const char* gradientTValue,
bsalomon63e99f72014-07-21 08:03:14 -0700505 const char* outputColor,
506 const char* inputColor,
bsalomonb58a2b42016-09-26 06:55:02 -0700507 const TextureSamplers&);
bsalomon63e99f72014-07-21 08:03:14 -0700508
509private:
Florin Malitab81a8b92017-08-08 12:14:17 -0400510 void emitAnalyticalColor(GrGLSLFPFragmentBuilder* fragBuilder,
511 GrGLSLUniformHandler* uniformHandler,
512 const GrShaderCaps* shaderCaps,
513 const GrGradientEffect&,
514 const char* gradientTValue,
515 const char* outputColor,
516 const char* inputColor);
517
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000518 enum {
fmenozzi64e8e5d2016-07-19 10:45:57 -0700519 // First bit for premul before/after interp
fmenozzicd9a1d02016-08-15 07:03:47 -0700520 kPremulBeforeInterpKey = 1,
bsalomon@google.com82d12232013-09-09 15:36:26 +0000521
fmenozzicd9a1d02016-08-15 07:03:47 -0700522 // Next three bits for 2/3 color type or different special
523 // hard stop cases (neither means using texture atlas)
524 kTwoColorKey = 2,
525 kThreeColorKey = 4,
Brian Salomonf8480b92017-07-27 15:45:59 -0400526
Brian Osman2ab4b2b2017-09-12 11:20:56 -0400527 kHardStopCenteredKey = 6,
528 kHardStopZeroZeroOneKey = 8,
529 kHardStopZeroOneOneKey = 10,
fmenozzicd9a1d02016-08-15 07:03:47 -0700530
531 // Next two bits for tile mode
532 kClampTileMode = 16,
533 kRepeatTileMode = 32,
534 kMirrorTileMode = 48,
535
536 // Lower six bits for premul, 2/3 color type, and tile mode
537 kReservedBits = 6,
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000538 };
539
bsalomon@google.com81712882012-11-01 17:12:34 +0000540 SkScalar fCachedYCoord;
fmenozzicd9a1d02016-08-15 07:03:47 -0700541 GrGLSLProgramDataManager::UniformHandle fColorsUni;
Brian Osmana8e57442017-09-11 17:21:35 -0400542 GrGLSLProgramDataManager::UniformHandle fExtraStopT;
egdaniel018fb622015-10-28 07:26:40 -0700543 GrGLSLProgramDataManager::UniformHandle fFSYUni;
Brian Osmanc624d9d2017-03-08 11:42:02 -0500544 GrGLSLColorSpaceXformHelper fColorSpaceHelper;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000545
egdaniel64c47282015-11-13 06:54:19 -0800546 typedef GrGLSLFragmentProcessor INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000547};
548
549#endif
550
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000551#endif