blob: 775cb39b8570e2f3ac6ad8c741ca79a962b7de80 [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
Florin Malita4aed1382017-05-25 10:38:07 -0400148 class GradientShaderBaseContext : public Context {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000149 public:
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000150 GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000151
mtklein36352bf2015-03-25 18:17:31 -0700152 uint32_t getFlags() const override { return fFlags; }
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000153
fmalita088e21b2016-10-05 09:28:42 -0700154 bool isValid() const;
155
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000156 protected:
157 SkMatrix fDstToIndex;
Cary Clark9480d822017-10-19 18:01:13 -0400158 SkMatrixPriv::MapXYProc fDstToIndexProc;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000159 uint8_t fDstToIndexClass;
160 uint8_t fFlags;
161
Hal Canary67b39de2016-11-07 11:47:44 -0500162 sk_sp<GradientShaderCache> fCache;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000163
164 private:
Florin Malita4aed1382017-05-25 10:38:07 -0400165 typedef Context INHERITED;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000166 };
167
mtklein36352bf2015-03-25 18:17:31 -0700168 bool isOpaque() const override;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000169
brianosmand4546092016-09-22 12:31:58 -0700170 enum class GradientBitmapType : uint8_t {
171 kLegacy,
172 kSRGB,
173 kHalfFloat,
174 };
175
176 void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000177
178 enum {
179 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
180 /// it, use a larger cache.
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000181 kCache32Bits = 8,
reed@google.com60040292013-02-04 18:21:23 +0000182 kCache32Count = (1 << kCache32Bits),
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000183 kCache32Shift = 16 - kCache32Bits,
184 kSqrt32Shift = 8 - kCache32Bits,
185
186 /// This value is used to *read* the dither cache; it may be 0
187 /// if dithering is disabled.
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000188 kDitherStride32 = kCache32Count,
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000189 };
190
commit-bot@chromium.org6c5aea22014-04-22 16:25:15 +0000191 uint32_t getGradFlags() const { return fGradFlags; }
commit-bot@chromium.org53783b02014-04-17 21:09:49 +0000192
Florin Malita0e36b3f2017-06-05 23:33:45 -0400193 SkColor4f getXformedColor(size_t index, SkColorSpace*) const;
194
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000195protected:
Mike Kleina3771842017-05-04 19:38:48 -0400196 struct Rec {
197 SkFixed fPos; // 0...1
198 uint32_t fScale; // (1 << 24) / range
199 };
200
fmalitabc590c02016-02-22 09:12:33 -0800201 class GradientShaderBase4fContext;
202
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000203 SkGradientShaderBase(SkReadBuffer& );
mtklein36352bf2015-03-25 18:17:31 -0700204 void flatten(SkWriteBuffer&) const override;
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000205 SK_TO_STRING_OVERRIDE()
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000206
Florin Malita5f379a82017-10-18 16:22:35 -0400207 void commonAsAGradient(GradientInfo*) const;
skia.committer@gmail.comd3b28e82014-04-22 03:05:17 +0000208
mtklein36352bf2015-03-25 18:17:31 -0700209 bool onAsLuminanceColor(SkColor*) const override;
reed8367b8c2014-08-22 08:30:20 -0700210
brianosmand4546092016-09-22 12:31:58 -0700211 void initLinearBitmap(SkBitmap* bitmap) const;
212
Mike Reed1d8c42e2017-08-29 14:58:19 -0400213 bool onAppendStages(const StageRec&) const override;
Mike Kleina3771842017-05-04 19:38:48 -0400214
Florin Malita50b20842017-07-29 19:08:28 -0400215 virtual void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
216 SkRasterPipeline* postPipeline) const = 0;
Mike Kleina3771842017-05-04 19:38:48 -0400217
fmalita088e21b2016-10-05 09:28:42 -0700218 template <typename T, typename... Args>
Herb Derby83e939b2017-02-07 14:25:11 -0500219 static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
220 auto* ctx = alloc->make<T>(std::forward<Args>(args)...);
fmalita088e21b2016-10-05 09:28:42 -0700221 if (!ctx->isValid()) {
fmalita088e21b2016-10-05 09:28:42 -0700222 return nullptr;
223 }
224 return ctx;
225 }
226
Mike Kleina3771842017-05-04 19:38:48 -0400227 const SkMatrix fPtsToUnit;
228 TileMode fTileMode;
229 TileProc fTileProc;
230 uint8_t fGradFlags;
231 Rec* fRecs;
232
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000233private:
234 enum {
235 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
236
brianosmanb9c51372016-09-15 11:09:45 -0700237 kStorageSize = kColorStorageCount *
238 (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec) + sizeof(SkColor4f))
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000239 };
brianosmanb9c51372016-09-15 11:09:45 -0700240 SkColor fStorage[(kStorageSize + 3) >> 2];
reedf3182eb2015-11-17 08:12:19 -0800241public:
brianosmanb9c51372016-09-15 11:09:45 -0700242 SkColor* fOrigColors; // original colors, before modulation by paint in context.
243 SkColor4f* fOrigColors4f; // original colors, as linear floats
244 SkScalar* fOrigPos; // original positions
245 int fColorCount;
246 sk_sp<SkColorSpace> fColorSpace; // color space of gradient stops
reedf3182eb2015-11-17 08:12:19 -0800247
248 bool colorsAreOpaque() const { return fColorsAreOpaque; }
249
fmenozzicd9a1d02016-08-15 07:03:47 -0700250 TileMode getTileMode() const { return fTileMode; }
251 Rec* getRecs() const { return fRecs; }
252
reedf3182eb2015-11-17 08:12:19 -0800253private:
brianosmanb9c51372016-09-15 11:09:45 -0700254 bool fColorsAreOpaque;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000255
Florin Malitacc586642017-10-24 16:18:59 -0400256 sk_sp<GradientShaderCache> refCache() const;
Hal Canary67b39de2016-11-07 11:47:44 -0500257 mutable SkMutex fCacheMutex;
258 mutable sk_sp<GradientShaderCache> fCache;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000259
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000260 void initCommon();
261
Florin Malita4aed1382017-05-25 10:38:07 -0400262 typedef SkShaderBase INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000263};
264
Mike Kleina3771842017-05-04 19:38:48 -0400265
reed@google.com55853db2013-02-01 19:34:59 +0000266static inline int init_dither_toggle(int x, int y) {
reed@google.com60040292013-02-04 18:21:23 +0000267 x &= 1;
268 y = (y & 1) << 1;
269 return (x | y) * SkGradientShaderBase::kDitherStride32;
reed@google.com55853db2013-02-01 19:34:59 +0000270}
271
272static inline int next_dither_toggle(int toggle) {
273 return toggle ^ SkGradientShaderBase::kDitherStride32;
274}
275
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000276///////////////////////////////////////////////////////////////////////////////
277
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000278#if SK_SUPPORT_GPU
279
brianosmanb9c51372016-09-15 11:09:45 -0700280#include "GrColorSpaceXform.h"
bsalomon@google.com77af6802013-10-02 13:04:56 +0000281#include "GrCoordTransform.h"
bsalomon6251d172014-10-15 10:50:36 -0700282#include "GrFragmentProcessor.h"
egdaniel64c47282015-11-13 06:54:19 -0800283#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel018fb622015-10-28 07:26:40 -0700284#include "glsl/GrGLSLProgramDataManager.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000285
egdaniel605dd0f2014-11-12 08:35:25 -0800286class GrInvariantOutput;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000287
288/*
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000289 * The interpretation of the texture matrix depends on the sample mode. The
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000290 * texture matrix is applied both when the texture coordinates are explicit
291 * and when vertex positions are used as texture coordinates. In the latter
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000292 * case the texture matrix is applied to the pre-view-matrix position
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000293 * values.
294 *
295 * Normal SampleMode
296 * The post-matrix texture coordinates are in normalize space with (0,0) at
297 * the top-left and (1,1) at the bottom right.
298 * RadialGradient
299 * The matrix specifies the radial gradient parameters.
300 * (0,0) in the post-matrix space is center of the radial gradient.
301 * Radial2Gradient
302 * Matrix transforms to space where first circle is centered at the
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000303 * origin. The second circle will be centered (x, 0) where x may be
304 * 0 and is provided by setRadial2Params. The post-matrix space is
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000305 * normalized such that 1 is the second radius - first radius.
306 * SweepGradient
307 * The angle from the origin of texture coordinates in post-matrix space
308 * determines the gradient value.
309 */
310
rileya@google.comb3e50f22012-08-20 17:43:08 +0000311 class GrTextureStripAtlas;
312
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000313// Base class for Gr gradient effects
joshualittb0a8a372014-09-23 09:50:21 -0700314class GrGradientEffect : public GrFragmentProcessor {
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000315public:
brianosman9557c272016-09-15 06:59:15 -0700316 struct CreateArgs {
317 CreateArgs(GrContext* context,
318 const SkGradientShaderBase* shader,
319 const SkMatrix* matrix,
brianosmanb9c51372016-09-15 11:09:45 -0700320 SkShader::TileMode tileMode,
Brian Osman5911a7c2017-10-25 12:52:31 -0400321 const SkColorSpace* dstColorSpace)
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400322 : fContext(context)
323 , fShader(shader)
324 , fMatrix(matrix)
Brian Osman5911a7c2017-10-25 12:52:31 -0400325 , fDstColorSpace(dstColorSpace) {
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400326 switch (tileMode) {
327 case SkShader::kClamp_TileMode:
328 fWrapMode = GrSamplerState::WrapMode::kClamp;
329 break;
330 case SkShader::kRepeat_TileMode:
331 fWrapMode = GrSamplerState::WrapMode::kRepeat;
332 break;
333 case SkShader::kMirror_TileMode:
334 fWrapMode = GrSamplerState::WrapMode::kMirrorRepeat;
335 break;
336 }
337 }
338
339 CreateArgs(GrContext* context,
340 const SkGradientShaderBase* shader,
341 const SkMatrix* matrix,
342 GrSamplerState::WrapMode wrapMode,
Brian Osman5911a7c2017-10-25 12:52:31 -0400343 const SkColorSpace* dstColorSpace)
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400344 : fContext(context)
345 , fShader(shader)
346 , fMatrix(matrix)
347 , fWrapMode(wrapMode)
Brian Osman5911a7c2017-10-25 12:52:31 -0400348 , fDstColorSpace(dstColorSpace) {}
brianosman9557c272016-09-15 06:59:15 -0700349
350 GrContext* fContext;
351 const SkGradientShaderBase* fShader;
352 const SkMatrix* fMatrix;
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400353 GrSamplerState::WrapMode fWrapMode;
Brian Osman5911a7c2017-10-25 12:52:31 -0400354 const SkColorSpace* fDstColorSpace;
brianosman9557c272016-09-15 06:59:15 -0700355 };
356
fmenozzi55d318d2016-08-09 08:05:57 -0700357 class GLSLProcessor;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000358
Brian Salomond3b65972017-03-22 12:05:03 -0400359 ~GrGradientEffect() override;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000360
rileya@google.comb3e50f22012-08-20 17:43:08 +0000361 bool useAtlas() const { return SkToBool(-1 != fRow); }
fmenozzicd9a1d02016-08-15 07:03:47 -0700362 SkScalar getYCoord() const { return fYCoord; }
rileya@google.comb3e50f22012-08-20 17:43:08 +0000363
fmenozzicd9a1d02016-08-15 07:03:47 -0700364 enum ColorType {
365 kTwo_ColorType,
Brian Osmana8e57442017-09-11 17:21:35 -0400366 kThree_ColorType, // 0, t, 1
fmenozzicd9a1d02016-08-15 07:03:47 -0700367 kTexture_ColorType,
Brian Salomon466ad992016-10-13 16:08:36 -0400368 kSingleHardStop_ColorType, // 0, t, t, 1
fmenozzicd9a1d02016-08-15 07:03:47 -0700369 kHardStopLeftEdged_ColorType, // 0, 0, 1
370 kHardStopRightEdged_ColorType, // 0, 1, 1
fmenozzicd9a1d02016-08-15 07:03:47 -0700371 };
372
373 ColorType getColorType() const { return fColorType; }
374
375 // Determines the type of gradient, one of:
376 // - Two-color
377 // - Symmetric three-color
378 // - Texture
379 // - Centered hard stop
380 // - Left-edged hard stop
381 // - Right-edged hard stop
382 ColorType determineColorType(const SkGradientShaderBase& shader);
bsalomon@google.com82d12232013-09-09 15:36:26 +0000383
384 enum PremulType {
385 kBeforeInterp_PremulType,
386 kAfterInterp_PremulType,
387 };
388
389 PremulType getPremulType() const { return fPremulType; }
390
Brian Osmand43f7b62017-10-19 15:42:01 -0400391 const GrColor4f* getColors4f(int pos) const {
brianosmanb9c51372016-09-15 11:09:45 -0700392 SkASSERT(fColorType != kTexture_ColorType);
393 SkASSERT(pos < fColors4f.count());
394 return &fColors4f[pos];
395 }
396
bsalomon@google.comd4726202012-08-03 14:34:46 +0000397protected:
Ethan Nicholasabff9562017-10-09 10:54:08 -0400398 GrGradientEffect(ClassID classID, const CreateArgs&, bool isOpaque);
Brian Salomonf8480b92017-07-27 15:45:59 -0400399 explicit GrGradientEffect(const GrGradientEffect&); // facilitates clone() implementations
Brian Salomon587e08f2017-01-27 10:59:27 -0500400
Brian Osman5911a7c2017-10-25 12:52:31 -0400401 // Helper function used by derived class factories to handle color space transformation and
402 // modulation by input alpha.
403 static std::unique_ptr<GrFragmentProcessor> AdjustFP(
404 std::unique_ptr<GrGradientEffect> gradientFP, const CreateArgs& args) {
405 if (!gradientFP->isValid()) {
406 return nullptr;
407 }
408 std::unique_ptr<GrFragmentProcessor> fp;
409 // With analytic gradients, we pre-convert the stops to the destination color space, so no
410 // xform is needed. With texture-based gradients, we leave the data in the source color
411 // space (to avoid clamping if we can't use F16)... Add an extra FP to do the xform.
412 if (kTexture_ColorType == gradientFP->getColorType()) {
413 fp = GrColorSpaceXformEffect::Make(std::move(gradientFP),
414 args.fShader->fColorSpace.get(),
415 args.fDstColorSpace);
416 } else {
417 fp = std::move(gradientFP);
418 }
419 return GrFragmentProcessor::MulOutputByInputAlpha(std::move(fp));
420 }
421
422#if GR_TEST_UTILS
Brian Osmane75c19f2016-10-10 11:26:43 -0400423 /** Helper struct that stores (and populates) parameters to construct a random gradient.
Brian Osmana2196532016-10-17 12:48:13 -0400424 If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and
425 fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount
426 will be the number of color stops in either case, and fColors and fStops can be passed to
427 the gradient factory. (The constructor may decide not to use stops, in which case fStops
428 will be nullptr). */
Brian Osman3f748602016-10-03 18:29:03 -0400429 struct RandomGradientParams {
Brian Salomon5d4cd9e2017-02-09 11:16:46 -0500430 static const int kMaxRandomGradientColors = 5;
Brian Osmane75c19f2016-10-10 11:26:43 -0400431
Brian Osman3f748602016-10-03 18:29:03 -0400432 RandomGradientParams(SkRandom* r);
433
Brian Osmana2196532016-10-17 12:48:13 -0400434 bool fUseColors4f;
Brian Osman3f748602016-10-03 18:29:03 -0400435 SkColor fColors[kMaxRandomGradientColors];
Brian Osmana2196532016-10-17 12:48:13 -0400436 SkColor4f fColors4f[kMaxRandomGradientColors];
437 sk_sp<SkColorSpace> fColorSpace;
Brian Osman3f748602016-10-03 18:29:03 -0400438 SkScalar fStopStorage[kMaxRandomGradientColors];
439 SkShader::TileMode fTileMode;
440 int fColorCount;
441 SkScalar* fStops;
442 };
Hal Canary6f6961e2017-01-31 13:50:44 -0500443 #endif
bsalomon@google.comd4726202012-08-03 14:34:46 +0000444
mtklein36352bf2015-03-25 18:17:31 -0700445 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000446
commit-bot@chromium.org5fd7d5c2013-10-04 01:20:09 +0000447 const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
448
Brian Salomon6af27012017-06-09 08:21:42 -0400449 /** Checks whether the constructor failed to fully initialize the processor. */
Brian Salomon06e547c2017-06-09 16:11:32 -0400450 bool isValid() const {
451 return fColorType != kTexture_ColorType || fTextureSampler.isInitialized();
452 }
Brian Salomon6af27012017-06-09 08:21:42 -0400453
bsalomon@google.comd4726202012-08-03 14:34:46 +0000454private:
Brian Salomon587e08f2017-01-27 10:59:27 -0500455 static OptimizationFlags OptFlags(bool isOpaque);
456
Brian Osmand43f7b62017-10-19 15:42:01 -0400457 SkTDArray<GrColor4f> fColors4f;
brianosmanb9c51372016-09-15 11:09:45 -0700458
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400459 SkTDArray<SkScalar> fPositions;
460 GrSamplerState::WrapMode fWrapMode;
fmenozzicd9a1d02016-08-15 07:03:47 -0700461
bsalomon@google.com77af6802013-10-02 13:04:56 +0000462 GrCoordTransform fCoordTransform;
Brian Salomon0bbecb22016-11-17 11:38:22 -0500463 TextureSampler fTextureSampler;
bsalomon@google.com81712882012-11-01 17:12:34 +0000464 SkScalar fYCoord;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000465 GrTextureStripAtlas* fAtlas;
466 int fRow;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000467 bool fIsOpaque;
fmenozzicd9a1d02016-08-15 07:03:47 -0700468 ColorType fColorType;
469 PremulType fPremulType; // This is already baked into the table for texture gradients, and
470 // only changes behavior for gradients that don't use a texture.
joshualittb0a8a372014-09-23 09:50:21 -0700471 typedef GrFragmentProcessor INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000472
473};
474
475///////////////////////////////////////////////////////////////////////////////
476
fmenozzicd9a1d02016-08-15 07:03:47 -0700477// Base class for GL gradient effects
fmenozzi55d318d2016-08-09 08:05:57 -0700478class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000479public:
fmenozzicd9a1d02016-08-15 07:03:47 -0700480 GLSLProcessor() {
481 fCachedYCoord = SK_ScalarMax;
482 }
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000483
wangyixb1daa862015-08-18 11:29:31 -0700484protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400485 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000486
bsalomon@google.comf78df332012-10-29 12:43:38 +0000487protected:
bsalomon63e99f72014-07-21 08:03:14 -0700488 /**
489 * Subclasses must call this. It will return a key for the part of the shader code controlled
490 * by the base class. The subclasses must stick it in their key and then pass it to the below
491 * emit* functions from their emitCode function.
492 */
joshualittb0a8a372014-09-23 09:50:21 -0700493 static uint32_t GenBaseGradientKey(const GrProcessor&);
bsalomon63e99f72014-07-21 08:03:14 -0700494
495 // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
496 // should call this method from their emitCode().
egdaniel7ea439b2015-12-03 09:20:44 -0800497 void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
bsalomon63e99f72014-07-21 08:03:14 -0700498
fmenozzicd9a1d02016-08-15 07:03:47 -0700499 // Emit code that gets a fragment's color from an expression for t; has branches for
500 // several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+
501 // color gradients that use the traditional texture lookup, as well as several varieties
502 // of hard stop gradients
cdalton85285412016-02-18 12:37:07 -0800503 void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
egdaniel7ea439b2015-12-03 09:20:44 -0800504 GrGLSLUniformHandler* uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500505 const GrShaderCaps* shaderCaps,
joshualitt60030bc2014-11-25 14:21:55 -0800506 const GrGradientEffect&,
bsalomon63e99f72014-07-21 08:03:14 -0700507 const char* gradientTValue,
bsalomon63e99f72014-07-21 08:03:14 -0700508 const char* outputColor,
509 const char* inputColor,
bsalomonb58a2b42016-09-26 06:55:02 -0700510 const TextureSamplers&);
bsalomon63e99f72014-07-21 08:03:14 -0700511
512private:
Florin Malitab81a8b92017-08-08 12:14:17 -0400513 void emitAnalyticalColor(GrGLSLFPFragmentBuilder* fragBuilder,
514 GrGLSLUniformHandler* uniformHandler,
515 const GrShaderCaps* shaderCaps,
516 const GrGradientEffect&,
517 const char* gradientTValue,
518 const char* outputColor,
519 const char* inputColor);
520
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000521 enum {
Brian Osmanfe3e8582017-10-20 11:27:49 -0400522 // First bit for premul before/after interpolation
fmenozzicd9a1d02016-08-15 07:03:47 -0700523 kPremulBeforeInterpKey = 1,
bsalomon@google.com82d12232013-09-09 15:36:26 +0000524
fmenozzicd9a1d02016-08-15 07:03:47 -0700525 // Next three bits for 2/3 color type or different special
Brian Osmanfe3e8582017-10-20 11:27:49 -0400526 // hard stop cases ('none' means using texture atlas)
fmenozzicd9a1d02016-08-15 07:03:47 -0700527 kTwoColorKey = 2,
528 kThreeColorKey = 4,
Brian Salomonf8480b92017-07-27 15:45:59 -0400529
Brian Osman2ab4b2b2017-09-12 11:20:56 -0400530 kHardStopCenteredKey = 6,
531 kHardStopZeroZeroOneKey = 8,
532 kHardStopZeroOneOneKey = 10,
fmenozzicd9a1d02016-08-15 07:03:47 -0700533
534 // Next two bits for tile mode
535 kClampTileMode = 16,
536 kRepeatTileMode = 32,
537 kMirrorTileMode = 48,
538
539 // Lower six bits for premul, 2/3 color type, and tile mode
540 kReservedBits = 6,
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000541 };
542
bsalomon@google.com81712882012-11-01 17:12:34 +0000543 SkScalar fCachedYCoord;
fmenozzicd9a1d02016-08-15 07:03:47 -0700544 GrGLSLProgramDataManager::UniformHandle fColorsUni;
Brian Osmana8e57442017-09-11 17:21:35 -0400545 GrGLSLProgramDataManager::UniformHandle fExtraStopT;
egdaniel018fb622015-10-28 07:26:40 -0700546 GrGLSLProgramDataManager::UniformHandle fFSYUni;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000547
egdaniel64c47282015-11-13 06:54:19 -0800548 typedef GrGLSLFragmentProcessor INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000549};
550
551#endif
552
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000553#endif