blob: da9098cb5d8e15a84b31d0c236b37563f166345f [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"
Kevin Lubickc456b732017-01-11 17:21:57 +000019#include "SkOnce.h"
Mike Kleina3771842017-05-04 19:38:48 -040020#include "SkPM4fPriv.h"
21#include "SkRasterPipeline.h"
Hal Canary95e3c052017-01-11 12:44:43 -050022#include "SkReadBuffer.h"
Florin Malita4aed1382017-05-25 10:38:07 -040023#include "SkShaderBase.h"
Hal Canary95e3c052017-01-11 12:44:43 -050024#include "SkUtils.h"
25#include "SkWriteBuffer.h"
rileya@google.com1c6d64b2012-07-27 15:49:05 +000026
humper@google.com05af1af2013-01-07 16:47:43 +000027static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
rileya@google.com1c6d64b2012-07-27 15:49:05 +000028 int count) {
29 if (count > 0) {
30 if (v0 == v1) {
31 sk_memset32(dst, v0, count);
32 } else {
33 int pairs = count >> 1;
34 for (int i = 0; i < pairs; i++) {
35 *dst++ = v0;
36 *dst++ = v1;
37 }
38 if (count & 1) {
39 *dst = v0;
40 }
41 }
42 }
43}
44
45// Clamp
46
humper@google.com05af1af2013-01-07 16:47:43 +000047static inline SkFixed clamp_tileproc(SkFixed x) {
rileya@google.com1c6d64b2012-07-27 15:49:05 +000048 return SkClampMax(x, 0xFFFF);
49}
50
51// Repeat
52
humper@google.com05af1af2013-01-07 16:47:43 +000053static inline SkFixed repeat_tileproc(SkFixed x) {
rileya@google.com1c6d64b2012-07-27 15:49:05 +000054 return x & 0xFFFF;
55}
56
57// Mirror
58
rileya@google.com1c6d64b2012-07-27 15:49:05 +000059static inline SkFixed mirror_tileproc(SkFixed x) {
caryclark3127c992015-12-09 12:02:30 -080060 int s = SkLeftShift(x, 15) >> 31;
rileya@google.com1c6d64b2012-07-27 15:49:05 +000061 return (x ^ s) & 0xFFFF;
62}
63
rileya@google.com1c6d64b2012-07-27 15:49:05 +000064///////////////////////////////////////////////////////////////////////////////
65
66typedef SkFixed (*TileProc)(SkFixed);
67
68///////////////////////////////////////////////////////////////////////////////
69
70static const TileProc gTileProcs[] = {
71 clamp_tileproc,
72 repeat_tileproc,
73 mirror_tileproc
74};
75
76///////////////////////////////////////////////////////////////////////////////
77
Florin Malita4aed1382017-05-25 10:38:07 -040078class SkGradientShaderBase : public SkShaderBase {
rileya@google.com1c6d64b2012-07-27 15:49:05 +000079public:
reed@google.com437d6eb2013-05-23 19:03:05 +000080 struct Descriptor {
81 Descriptor() {
82 sk_bzero(this, sizeof(*this));
83 fTileMode = SkShader::kClamp_TileMode;
84 }
skia.committer@gmail.com3e2345a2013-05-24 07:01:26 +000085
reedaddf2ed2014-08-11 08:28:24 -070086 const SkMatrix* fLocalMatrix;
brianosmane25d71c2016-09-28 11:27:28 -070087 const SkColor4f* fColors;
brianosmanb9c51372016-09-15 11:09:45 -070088 sk_sp<SkColorSpace> fColorSpace;
reed@google.com437d6eb2013-05-23 19:03:05 +000089 const SkScalar* fPos;
90 int fCount;
91 SkShader::TileMode fTileMode;
commit-bot@chromium.org6c5aea22014-04-22 16:25:15 +000092 uint32_t fGradFlags;
reed9fa60da2014-08-21 07:59:51 -070093
94 void flatten(SkWriteBuffer&) const;
95 };
96
97 class DescriptorScope : public Descriptor {
98 public:
99 DescriptorScope() {}
mtklein88fd0fb2014-12-01 06:56:38 -0800100
reed9fa60da2014-08-21 07:59:51 -0700101 bool unflatten(SkReadBuffer&);
102
103 // fColors and fPos always point into local memory, so they can be safely mutated
104 //
brianosmane25d71c2016-09-28 11:27:28 -0700105 SkColor4f* mutableColors() { return const_cast<SkColor4f*>(fColors); }
reed9fa60da2014-08-21 07:59:51 -0700106 SkScalar* mutablePos() { return const_cast<SkScalar*>(fPos); }
107
108 private:
109 enum {
110 kStorageCount = 16
111 };
brianosmane25d71c2016-09-28 11:27:28 -0700112 SkColor4f fColorStorage[kStorageCount];
reed9fa60da2014-08-21 07:59:51 -0700113 SkScalar fPosStorage[kStorageCount];
114 SkMatrix fLocalMatrixStorage;
115 SkAutoMalloc fDynamicStorage;
reed@google.com437d6eb2013-05-23 19:03:05 +0000116 };
117
mtkleincc695fe2014-12-10 10:29:19 -0800118 SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit);
Brian Salomond3b65972017-03-22 12:05:03 -0400119 ~SkGradientShaderBase() override;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000120
brianosman93110a82016-09-15 08:40:21 -0700121 // The cache is initialized on-demand when getCache32 is called.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000122 class GradientShaderCache : public SkRefCnt {
123 public:
fmalita37d86882015-10-09 10:22:46 -0700124 GradientShaderCache(U8CPU alpha, bool dither, const SkGradientShaderBase& shader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000125 ~GradientShaderCache();
126
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000127 const SkPMColor* getCache32();
128
Mike Reed6b3155c2017-04-03 14:41:44 -0400129 SkPixelRef* getCache32PixelRef() const { return fCache32PixelRef.get(); }
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000130
131 unsigned getAlpha() const { return fCacheAlpha; }
fmalita37d86882015-10-09 10:22:46 -0700132 bool getDither() const { return fCacheDither; }
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000133
134 private:
brianosman93110a82016-09-15 08:40:21 -0700135 // Working pointer. If it's nullptr, we need to recompute the cache values.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000136 SkPMColor* fCache32;
137
Mike Reed6b3155c2017-04-03 14:41:44 -0400138 sk_sp<SkPixelRef> fCache32PixelRef;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000139 const unsigned fCacheAlpha; // The alpha value we used when we computed the cache.
140 // Larger than 8bits so we can store uninitialized
141 // value.
fmalita37d86882015-10-09 10:22:46 -0700142 const bool fCacheDither; // The dither flag used when we computed the cache.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000143
144 const SkGradientShaderBase& fShader;
145
brianosman93110a82016-09-15 08:40:21 -0700146 // Make sure we only initialize the cache once.
147 SkOnce fCache32InitOnce;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000148
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000149 static void initCache32(GradientShaderCache* cache);
150
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000151 static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
fmalita37d86882015-10-09 10:22:46 -0700152 U8CPU alpha, uint32_t gradFlags, bool dither);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000153 };
154
Florin Malita4aed1382017-05-25 10:38:07 -0400155 class GradientShaderBaseContext : public Context {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000156 public:
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000157 GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000158
mtklein36352bf2015-03-25 18:17:31 -0700159 uint32_t getFlags() const override { return fFlags; }
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000160
fmalita088e21b2016-10-05 09:28:42 -0700161 bool isValid() const;
162
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000163 protected:
164 SkMatrix fDstToIndex;
165 SkMatrix::MapXYProc fDstToIndexProc;
166 uint8_t fDstToIndexClass;
167 uint8_t fFlags;
fmalita37d86882015-10-09 10:22:46 -0700168 bool fDither;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000169
Hal Canary67b39de2016-11-07 11:47:44 -0500170 sk_sp<GradientShaderCache> fCache;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000171
172 private:
Florin Malita4aed1382017-05-25 10:38:07 -0400173 typedef Context INHERITED;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000174 };
175
mtklein36352bf2015-03-25 18:17:31 -0700176 bool isOpaque() const override;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000177
brianosmand4546092016-09-22 12:31:58 -0700178 enum class GradientBitmapType : uint8_t {
179 kLegacy,
180 kSRGB,
181 kHalfFloat,
182 };
183
184 void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000185
186 enum {
187 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
188 /// it, use a larger cache.
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000189 kCache32Bits = 8,
reed@google.com60040292013-02-04 18:21:23 +0000190 kCache32Count = (1 << kCache32Bits),
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000191 kCache32Shift = 16 - kCache32Bits,
192 kSqrt32Shift = 8 - kCache32Bits,
193
194 /// This value is used to *read* the dither cache; it may be 0
195 /// if dithering is disabled.
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000196 kDitherStride32 = kCache32Count,
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000197 };
198
commit-bot@chromium.org6c5aea22014-04-22 16:25:15 +0000199 uint32_t getGradFlags() const { return fGradFlags; }
commit-bot@chromium.org53783b02014-04-17 21:09:49 +0000200
Florin Malita0e36b3f2017-06-05 23:33:45 -0400201 SkColor4f getXformedColor(size_t index, SkColorSpace*) const;
202
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000203protected:
Mike Kleina3771842017-05-04 19:38:48 -0400204 struct Rec {
205 SkFixed fPos; // 0...1
206 uint32_t fScale; // (1 << 24) / range
207 };
208
fmalitabc590c02016-02-22 09:12:33 -0800209 class GradientShaderBase4fContext;
210
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000211 SkGradientShaderBase(SkReadBuffer& );
mtklein36352bf2015-03-25 18:17:31 -0700212 void flatten(SkWriteBuffer&) const override;
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000213 SK_TO_STRING_OVERRIDE()
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000214
Florin Malita5f379a82017-10-18 16:22:35 -0400215 void commonAsAGradient(GradientInfo*) const;
skia.committer@gmail.comd3b28e82014-04-22 03:05:17 +0000216
mtklein36352bf2015-03-25 18:17:31 -0700217 bool onAsLuminanceColor(SkColor*) const override;
reed8367b8c2014-08-22 08:30:20 -0700218
brianosmand4546092016-09-22 12:31:58 -0700219 void initLinearBitmap(SkBitmap* bitmap) const;
220
Mike Reed1d8c42e2017-08-29 14:58:19 -0400221 bool onAppendStages(const StageRec&) const override;
Mike Kleina3771842017-05-04 19:38:48 -0400222
Florin Malita50b20842017-07-29 19:08:28 -0400223 virtual void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
224 SkRasterPipeline* postPipeline) const = 0;
Mike Kleina3771842017-05-04 19:38:48 -0400225
fmalita088e21b2016-10-05 09:28:42 -0700226 template <typename T, typename... Args>
Herb Derby83e939b2017-02-07 14:25:11 -0500227 static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
228 auto* ctx = alloc->make<T>(std::forward<Args>(args)...);
fmalita088e21b2016-10-05 09:28:42 -0700229 if (!ctx->isValid()) {
fmalita088e21b2016-10-05 09:28:42 -0700230 return nullptr;
231 }
232 return ctx;
233 }
234
Mike Kleina3771842017-05-04 19:38:48 -0400235 const SkMatrix fPtsToUnit;
236 TileMode fTileMode;
237 TileProc fTileProc;
238 uint8_t fGradFlags;
239 Rec* fRecs;
240
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000241private:
242 enum {
243 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
244
brianosmanb9c51372016-09-15 11:09:45 -0700245 kStorageSize = kColorStorageCount *
246 (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec) + sizeof(SkColor4f))
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000247 };
brianosmanb9c51372016-09-15 11:09:45 -0700248 SkColor fStorage[(kStorageSize + 3) >> 2];
reedf3182eb2015-11-17 08:12:19 -0800249public:
brianosmanb9c51372016-09-15 11:09:45 -0700250 SkColor* fOrigColors; // original colors, before modulation by paint in context.
251 SkColor4f* fOrigColors4f; // original colors, as linear floats
252 SkScalar* fOrigPos; // original positions
253 int fColorCount;
254 sk_sp<SkColorSpace> fColorSpace; // color space of gradient stops
reedf3182eb2015-11-17 08:12:19 -0800255
256 bool colorsAreOpaque() const { return fColorsAreOpaque; }
257
fmenozzicd9a1d02016-08-15 07:03:47 -0700258 TileMode getTileMode() const { return fTileMode; }
259 Rec* getRecs() const { return fRecs; }
260
reedf3182eb2015-11-17 08:12:19 -0800261private:
brianosmanb9c51372016-09-15 11:09:45 -0700262 bool fColorsAreOpaque;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000263
Hal Canary67b39de2016-11-07 11:47:44 -0500264 sk_sp<GradientShaderCache> refCache(U8CPU alpha, bool dither) const;
265 mutable SkMutex fCacheMutex;
266 mutable sk_sp<GradientShaderCache> fCache;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000267
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000268 void initCommon();
269
Florin Malita4aed1382017-05-25 10:38:07 -0400270 typedef SkShaderBase INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000271};
272
Mike Kleina3771842017-05-04 19:38:48 -0400273
reed@google.com55853db2013-02-01 19:34:59 +0000274static inline int init_dither_toggle(int x, int y) {
reed@google.com60040292013-02-04 18:21:23 +0000275 x &= 1;
276 y = (y & 1) << 1;
277 return (x | y) * SkGradientShaderBase::kDitherStride32;
reed@google.com55853db2013-02-01 19:34:59 +0000278}
279
280static inline int next_dither_toggle(int toggle) {
281 return toggle ^ SkGradientShaderBase::kDitherStride32;
282}
283
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000284///////////////////////////////////////////////////////////////////////////////
285
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000286#if SK_SUPPORT_GPU
287
brianosmanb9c51372016-09-15 11:09:45 -0700288#include "GrColorSpaceXform.h"
bsalomon@google.com77af6802013-10-02 13:04:56 +0000289#include "GrCoordTransform.h"
bsalomon6251d172014-10-15 10:50:36 -0700290#include "GrFragmentProcessor.h"
Brian Osmanc624d9d2017-03-08 11:42:02 -0500291#include "glsl/GrGLSLColorSpaceXformHelper.h"
egdaniel64c47282015-11-13 06:54:19 -0800292#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel018fb622015-10-28 07:26:40 -0700293#include "glsl/GrGLSLProgramDataManager.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000294
egdaniel605dd0f2014-11-12 08:35:25 -0800295class GrInvariantOutput;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000296
297/*
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000298 * The interpretation of the texture matrix depends on the sample mode. The
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000299 * texture matrix is applied both when the texture coordinates are explicit
300 * and when vertex positions are used as texture coordinates. In the latter
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000301 * case the texture matrix is applied to the pre-view-matrix position
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000302 * values.
303 *
304 * Normal SampleMode
305 * The post-matrix texture coordinates are in normalize space with (0,0) at
306 * the top-left and (1,1) at the bottom right.
307 * RadialGradient
308 * The matrix specifies the radial gradient parameters.
309 * (0,0) in the post-matrix space is center of the radial gradient.
310 * Radial2Gradient
311 * Matrix transforms to space where first circle is centered at the
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000312 * origin. The second circle will be centered (x, 0) where x may be
313 * 0 and is provided by setRadial2Params. The post-matrix space is
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000314 * normalized such that 1 is the second radius - first radius.
315 * SweepGradient
316 * The angle from the origin of texture coordinates in post-matrix space
317 * determines the gradient value.
318 */
319
rileya@google.comb3e50f22012-08-20 17:43:08 +0000320 class GrTextureStripAtlas;
321
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000322// Base class for Gr gradient effects
joshualittb0a8a372014-09-23 09:50:21 -0700323class GrGradientEffect : public GrFragmentProcessor {
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000324public:
brianosman9557c272016-09-15 06:59:15 -0700325 struct CreateArgs {
326 CreateArgs(GrContext* context,
327 const SkGradientShaderBase* shader,
328 const SkMatrix* matrix,
brianosmanb9c51372016-09-15 11:09:45 -0700329 SkShader::TileMode tileMode,
330 sk_sp<GrColorSpaceXform> colorSpaceXform,
331 bool gammaCorrect)
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400332 : fContext(context)
333 , fShader(shader)
334 , fMatrix(matrix)
335 , fColorSpaceXform(std::move(colorSpaceXform))
336 , fGammaCorrect(gammaCorrect) {
337 switch (tileMode) {
338 case SkShader::kClamp_TileMode:
339 fWrapMode = GrSamplerState::WrapMode::kClamp;
340 break;
341 case SkShader::kRepeat_TileMode:
342 fWrapMode = GrSamplerState::WrapMode::kRepeat;
343 break;
344 case SkShader::kMirror_TileMode:
345 fWrapMode = GrSamplerState::WrapMode::kMirrorRepeat;
346 break;
347 }
348 }
349
350 CreateArgs(GrContext* context,
351 const SkGradientShaderBase* shader,
352 const SkMatrix* matrix,
353 GrSamplerState::WrapMode wrapMode,
354 sk_sp<GrColorSpaceXform> colorSpaceXform,
355 bool gammaCorrect)
356 : fContext(context)
357 , fShader(shader)
358 , fMatrix(matrix)
359 , fWrapMode(wrapMode)
360 , fColorSpaceXform(std::move(colorSpaceXform))
361 , fGammaCorrect(gammaCorrect) {}
brianosman9557c272016-09-15 06:59:15 -0700362
363 GrContext* fContext;
364 const SkGradientShaderBase* fShader;
365 const SkMatrix* fMatrix;
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400366 GrSamplerState::WrapMode fWrapMode;
brianosmanb9c51372016-09-15 11:09:45 -0700367 sk_sp<GrColorSpaceXform> fColorSpaceXform;
368 bool fGammaCorrect;
brianosman9557c272016-09-15 06:59:15 -0700369 };
370
fmenozzi55d318d2016-08-09 08:05:57 -0700371 class GLSLProcessor;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000372
Brian Salomond3b65972017-03-22 12:05:03 -0400373 ~GrGradientEffect() override;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000374
rileya@google.comb3e50f22012-08-20 17:43:08 +0000375 bool useAtlas() const { return SkToBool(-1 != fRow); }
fmenozzicd9a1d02016-08-15 07:03:47 -0700376 SkScalar getYCoord() const { return fYCoord; }
rileya@google.comb3e50f22012-08-20 17:43:08 +0000377
fmenozzicd9a1d02016-08-15 07:03:47 -0700378 enum ColorType {
379 kTwo_ColorType,
Brian Osmana8e57442017-09-11 17:21:35 -0400380 kThree_ColorType, // 0, t, 1
fmenozzicd9a1d02016-08-15 07:03:47 -0700381 kTexture_ColorType,
Brian Salomon466ad992016-10-13 16:08:36 -0400382 kSingleHardStop_ColorType, // 0, t, t, 1
fmenozzicd9a1d02016-08-15 07:03:47 -0700383 kHardStopLeftEdged_ColorType, // 0, 0, 1
384 kHardStopRightEdged_ColorType, // 0, 1, 1
fmenozzicd9a1d02016-08-15 07:03:47 -0700385 };
386
387 ColorType getColorType() const { return fColorType; }
388
389 // Determines the type of gradient, one of:
390 // - Two-color
391 // - Symmetric three-color
392 // - Texture
393 // - Centered hard stop
394 // - Left-edged hard stop
395 // - Right-edged hard stop
396 ColorType determineColorType(const SkGradientShaderBase& shader);
bsalomon@google.com82d12232013-09-09 15:36:26 +0000397
398 enum PremulType {
399 kBeforeInterp_PremulType,
400 kAfterInterp_PremulType,
401 };
402
403 PremulType getPremulType() const { return fPremulType; }
404
Brian Osmand43f7b62017-10-19 15:42:01 -0400405 const GrColor4f* getColors4f(int pos) const {
brianosmanb9c51372016-09-15 11:09:45 -0700406 SkASSERT(fColorType != kTexture_ColorType);
407 SkASSERT(pos < fColors4f.count());
408 return &fColors4f[pos];
409 }
410
bsalomon@google.comd4726202012-08-03 14:34:46 +0000411protected:
Ethan Nicholasabff9562017-10-09 10:54:08 -0400412 GrGradientEffect(ClassID classID, const CreateArgs&, bool isOpaque);
Brian Salomonf8480b92017-07-27 15:45:59 -0400413 explicit GrGradientEffect(const GrGradientEffect&); // facilitates clone() implementations
Brian Salomon587e08f2017-01-27 10:59:27 -0500414
Hal Canary6f6961e2017-01-31 13:50:44 -0500415 #if GR_TEST_UTILS
Brian Osmane75c19f2016-10-10 11:26:43 -0400416 /** Helper struct that stores (and populates) parameters to construct a random gradient.
Brian Osmana2196532016-10-17 12:48:13 -0400417 If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and
418 fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount
419 will be the number of color stops in either case, and fColors and fStops can be passed to
420 the gradient factory. (The constructor may decide not to use stops, in which case fStops
421 will be nullptr). */
Brian Osman3f748602016-10-03 18:29:03 -0400422 struct RandomGradientParams {
Brian Salomon5d4cd9e2017-02-09 11:16:46 -0500423 static const int kMaxRandomGradientColors = 5;
Brian Osmane75c19f2016-10-10 11:26:43 -0400424
Brian Osman3f748602016-10-03 18:29:03 -0400425 RandomGradientParams(SkRandom* r);
426
Brian Osmana2196532016-10-17 12:48:13 -0400427 bool fUseColors4f;
Brian Osman3f748602016-10-03 18:29:03 -0400428 SkColor fColors[kMaxRandomGradientColors];
Brian Osmana2196532016-10-17 12:48:13 -0400429 SkColor4f fColors4f[kMaxRandomGradientColors];
430 sk_sp<SkColorSpace> fColorSpace;
Brian Osman3f748602016-10-03 18:29:03 -0400431 SkScalar fStopStorage[kMaxRandomGradientColors];
432 SkShader::TileMode fTileMode;
433 int fColorCount;
434 SkScalar* fStops;
435 };
Hal Canary6f6961e2017-01-31 13:50:44 -0500436 #endif
bsalomon@google.comd4726202012-08-03 14:34:46 +0000437
mtklein36352bf2015-03-25 18:17:31 -0700438 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000439
commit-bot@chromium.org5fd7d5c2013-10-04 01:20:09 +0000440 const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
441
Brian Salomon6af27012017-06-09 08:21:42 -0400442 /** Checks whether the constructor failed to fully initialize the processor. */
Brian Salomon06e547c2017-06-09 16:11:32 -0400443 bool isValid() const {
444 return fColorType != kTexture_ColorType || fTextureSampler.isInitialized();
445 }
Brian Salomon6af27012017-06-09 08:21:42 -0400446
bsalomon@google.comd4726202012-08-03 14:34:46 +0000447private:
Brian Salomon587e08f2017-01-27 10:59:27 -0500448 static OptimizationFlags OptFlags(bool isOpaque);
449
Brian Osmand43f7b62017-10-19 15:42:01 -0400450 SkTDArray<GrColor4f> fColors4f;
brianosmanb9c51372016-09-15 11:09:45 -0700451
Brian Osmand43f7b62017-10-19 15:42:01 -0400452 // Only present if a color space transformation is needed
brianosmanb9c51372016-09-15 11:09:45 -0700453 sk_sp<GrColorSpaceXform> fColorSpaceXform;
454
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400455 SkTDArray<SkScalar> fPositions;
456 GrSamplerState::WrapMode fWrapMode;
fmenozzicd9a1d02016-08-15 07:03:47 -0700457
bsalomon@google.com77af6802013-10-02 13:04:56 +0000458 GrCoordTransform fCoordTransform;
Brian Salomon0bbecb22016-11-17 11:38:22 -0500459 TextureSampler fTextureSampler;
bsalomon@google.com81712882012-11-01 17:12:34 +0000460 SkScalar fYCoord;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000461 GrTextureStripAtlas* fAtlas;
462 int fRow;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000463 bool fIsOpaque;
fmenozzicd9a1d02016-08-15 07:03:47 -0700464 ColorType fColorType;
465 PremulType fPremulType; // This is already baked into the table for texture gradients, and
466 // only changes behavior for gradients that don't use a texture.
joshualittb0a8a372014-09-23 09:50:21 -0700467 typedef GrFragmentProcessor INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000468
469};
470
471///////////////////////////////////////////////////////////////////////////////
472
fmenozzicd9a1d02016-08-15 07:03:47 -0700473// Base class for GL gradient effects
fmenozzi55d318d2016-08-09 08:05:57 -0700474class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000475public:
fmenozzicd9a1d02016-08-15 07:03:47 -0700476 GLSLProcessor() {
477 fCachedYCoord = SK_ScalarMax;
478 }
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000479
wangyixb1daa862015-08-18 11:29:31 -0700480protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400481 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000482
bsalomon@google.comf78df332012-10-29 12:43:38 +0000483protected:
bsalomon63e99f72014-07-21 08:03:14 -0700484 /**
485 * Subclasses must call this. It will return a key for the part of the shader code controlled
486 * by the base class. The subclasses must stick it in their key and then pass it to the below
487 * emit* functions from their emitCode function.
488 */
joshualittb0a8a372014-09-23 09:50:21 -0700489 static uint32_t GenBaseGradientKey(const GrProcessor&);
bsalomon63e99f72014-07-21 08:03:14 -0700490
491 // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
492 // should call this method from their emitCode().
egdaniel7ea439b2015-12-03 09:20:44 -0800493 void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
bsalomon63e99f72014-07-21 08:03:14 -0700494
fmenozzicd9a1d02016-08-15 07:03:47 -0700495 // Emit code that gets a fragment's color from an expression for t; has branches for
496 // several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+
497 // color gradients that use the traditional texture lookup, as well as several varieties
498 // of hard stop gradients
cdalton85285412016-02-18 12:37:07 -0800499 void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel7ea439b2015-12-03 09:20:44 -0800500 GrGLSLUniformHandler* uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500501 const GrShaderCaps* shaderCaps,
joshualitt60030bc2014-11-25 14:21:55 -0800502 const GrGradientEffect&,
bsalomon63e99f72014-07-21 08:03:14 -0700503 const char* gradientTValue,
bsalomon63e99f72014-07-21 08:03:14 -0700504 const char* outputColor,
505 const char* inputColor,
bsalomonb58a2b42016-09-26 06:55:02 -0700506 const TextureSamplers&);
bsalomon63e99f72014-07-21 08:03:14 -0700507
508private:
Florin Malitab81a8b92017-08-08 12:14:17 -0400509 void emitAnalyticalColor(GrGLSLFPFragmentBuilder* fragBuilder,
510 GrGLSLUniformHandler* uniformHandler,
511 const GrShaderCaps* shaderCaps,
512 const GrGradientEffect&,
513 const char* gradientTValue,
514 const char* outputColor,
515 const char* inputColor);
516
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000517 enum {
fmenozzi64e8e5d2016-07-19 10:45:57 -0700518 // First bit for premul before/after interp
fmenozzicd9a1d02016-08-15 07:03:47 -0700519 kPremulBeforeInterpKey = 1,
bsalomon@google.com82d12232013-09-09 15:36:26 +0000520
fmenozzicd9a1d02016-08-15 07:03:47 -0700521 // Next three bits for 2/3 color type or different special
522 // hard stop cases (neither means using texture atlas)
523 kTwoColorKey = 2,
524 kThreeColorKey = 4,
Brian Salomonf8480b92017-07-27 15:45:59 -0400525
Brian Osman2ab4b2b2017-09-12 11:20:56 -0400526 kHardStopCenteredKey = 6,
527 kHardStopZeroZeroOneKey = 8,
528 kHardStopZeroOneOneKey = 10,
fmenozzicd9a1d02016-08-15 07:03:47 -0700529
530 // Next two bits for tile mode
531 kClampTileMode = 16,
532 kRepeatTileMode = 32,
533 kMirrorTileMode = 48,
534
535 // Lower six bits for premul, 2/3 color type, and tile mode
536 kReservedBits = 6,
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000537 };
538
bsalomon@google.com81712882012-11-01 17:12:34 +0000539 SkScalar fCachedYCoord;
fmenozzicd9a1d02016-08-15 07:03:47 -0700540 GrGLSLProgramDataManager::UniformHandle fColorsUni;
Brian Osmana8e57442017-09-11 17:21:35 -0400541 GrGLSLProgramDataManager::UniformHandle fExtraStopT;
egdaniel018fb622015-10-28 07:26:40 -0700542 GrGLSLProgramDataManager::UniformHandle fFSYUni;
Brian Osmanc624d9d2017-03-08 11:42:02 -0500543 GrGLSLColorSpaceXformHelper fColorSpaceHelper;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000544
egdaniel64c47282015-11-13 06:54:19 -0800545 typedef GrGLSLFragmentProcessor INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000546};
547
548#endif
549
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000550#endif