Line data Source code
1 : /*
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 :
11 : #include "SkGradientBitmapCache.h"
12 : #include "SkGradientShader.h"
13 :
14 : #include "SkArenaAlloc.h"
15 : #include "SkAutoMalloc.h"
16 : #include "SkClampRange.h"
17 : #include "SkColorPriv.h"
18 : #include "SkColorSpace.h"
19 : #include "SkOnce.h"
20 : #include "SkReadBuffer.h"
21 : #include "SkShader.h"
22 : #include "SkUtils.h"
23 : #include "SkWriteBuffer.h"
24 :
25 : #if SK_SUPPORT_GPU
26 : #define GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1
27 : #endif
28 :
29 3335 : static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
30 : int count) {
31 3335 : if (count > 0) {
32 3335 : if (v0 == v1) {
33 3335 : sk_memset32(dst, v0, count);
34 : } else {
35 0 : int pairs = count >> 1;
36 0 : for (int i = 0; i < pairs; i++) {
37 0 : *dst++ = v0;
38 0 : *dst++ = v1;
39 : }
40 0 : if (count & 1) {
41 0 : *dst = v0;
42 : }
43 : }
44 : }
45 3335 : }
46 :
47 : // Clamp
48 :
49 0 : static inline SkFixed clamp_tileproc(SkFixed x) {
50 0 : return SkClampMax(x, 0xFFFF);
51 : }
52 :
53 : // Repeat
54 :
55 2816 : static inline SkFixed repeat_tileproc(SkFixed x) {
56 2816 : return x & 0xFFFF;
57 : }
58 :
59 : // Mirror
60 :
61 0 : static inline SkFixed mirror_tileproc(SkFixed x) {
62 0 : int s = SkLeftShift(x, 15) >> 31;
63 0 : return (x ^ s) & 0xFFFF;
64 : }
65 :
66 : ///////////////////////////////////////////////////////////////////////////////
67 :
68 : typedef SkFixed (*TileProc)(SkFixed);
69 :
70 : ///////////////////////////////////////////////////////////////////////////////
71 :
72 : static const TileProc gTileProcs[] = {
73 : clamp_tileproc,
74 : repeat_tileproc,
75 : mirror_tileproc
76 : };
77 :
78 : ///////////////////////////////////////////////////////////////////////////////
79 :
80 : class SkGradientShaderBase : public SkShader {
81 : public:
82 25 : struct Descriptor {
83 25 : Descriptor() {
84 25 : sk_bzero(this, sizeof(*this));
85 25 : fTileMode = SkShader::kClamp_TileMode;
86 25 : }
87 :
88 : const SkMatrix* fLocalMatrix;
89 : const SkColor4f* fColors;
90 : sk_sp<SkColorSpace> fColorSpace;
91 : const SkScalar* fPos;
92 : int fCount;
93 : SkShader::TileMode fTileMode;
94 : uint32_t fGradFlags;
95 :
96 : void flatten(SkWriteBuffer&) const;
97 : };
98 :
99 0 : class DescriptorScope : public Descriptor {
100 : public:
101 0 : DescriptorScope() {}
102 :
103 : bool unflatten(SkReadBuffer&);
104 :
105 : // fColors and fPos always point into local memory, so they can be safely mutated
106 : //
107 0 : SkColor4f* mutableColors() { return const_cast<SkColor4f*>(fColors); }
108 0 : SkScalar* mutablePos() { return const_cast<SkScalar*>(fPos); }
109 :
110 : private:
111 : enum {
112 : kStorageCount = 16
113 : };
114 : SkColor4f fColorStorage[kStorageCount];
115 : SkScalar fPosStorage[kStorageCount];
116 : SkMatrix fLocalMatrixStorage;
117 : SkAutoMalloc fDynamicStorage;
118 : };
119 :
120 : SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit);
121 : ~SkGradientShaderBase() override;
122 :
123 : // The cache is initialized on-demand when getCache32 is called.
124 : class GradientShaderCache : public SkRefCnt {
125 : public:
126 : GradientShaderCache(U8CPU alpha, bool dither, const SkGradientShaderBase& shader);
127 : ~GradientShaderCache();
128 :
129 : const SkPMColor* getCache32();
130 :
131 0 : SkPixelRef* getCache32PixelRef() const { return fCache32PixelRef.get(); }
132 :
133 0 : unsigned getAlpha() const { return fCacheAlpha; }
134 0 : bool getDither() const { return fCacheDither; }
135 :
136 : private:
137 : // Working pointer. If it's nullptr, we need to recompute the cache values.
138 : SkPMColor* fCache32;
139 :
140 : sk_sp<SkPixelRef> fCache32PixelRef;
141 : const unsigned fCacheAlpha; // The alpha value we used when we computed the cache.
142 : // Larger than 8bits so we can store uninitialized
143 : // value.
144 : const bool fCacheDither; // The dither flag used when we computed the cache.
145 :
146 : const SkGradientShaderBase& fShader;
147 :
148 : // Make sure we only initialize the cache once.
149 : SkOnce fCache32InitOnce;
150 :
151 : static void initCache32(GradientShaderCache* cache);
152 :
153 : static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
154 : U8CPU alpha, uint32_t gradFlags, bool dither);
155 : };
156 :
157 25 : class GradientShaderBaseContext : public SkShader::Context {
158 : public:
159 : GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&);
160 :
161 556 : uint32_t getFlags() const override { return fFlags; }
162 :
163 : bool isValid() const;
164 :
165 : protected:
166 : SkMatrix fDstToIndex;
167 : SkMatrix::MapXYProc fDstToIndexProc;
168 : uint8_t fDstToIndexClass;
169 : uint8_t fFlags;
170 : bool fDither;
171 :
172 : sk_sp<GradientShaderCache> fCache;
173 :
174 : private:
175 : typedef SkShader::Context INHERITED;
176 : };
177 :
178 : bool isOpaque() const override;
179 :
180 : enum class GradientBitmapType : uint8_t {
181 : kLegacy,
182 : kSRGB,
183 : kHalfFloat,
184 : };
185 :
186 : void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const;
187 :
188 : enum {
189 : /// Seems like enough for visual accuracy. TODO: if pos[] deserves
190 : /// it, use a larger cache.
191 : kCache32Bits = 8,
192 : kCache32Count = (1 << kCache32Bits),
193 : kCache32Shift = 16 - kCache32Bits,
194 : kSqrt32Shift = 8 - kCache32Bits,
195 :
196 : /// This value is used to *read* the dither cache; it may be 0
197 : /// if dithering is disabled.
198 : kDitherStride32 = kCache32Count,
199 : };
200 :
201 25 : uint32_t getGradFlags() const { return fGradFlags; }
202 :
203 : protected:
204 : class GradientShaderBase4fContext;
205 :
206 : SkGradientShaderBase(SkReadBuffer& );
207 : void flatten(SkWriteBuffer&) const override;
208 : SK_TO_STRING_OVERRIDE()
209 :
210 : const SkMatrix fPtsToUnit;
211 : TileMode fTileMode;
212 : TileProc fTileProc;
213 : uint8_t fGradFlags;
214 :
215 : struct Rec {
216 : SkFixed fPos; // 0...1
217 : uint32_t fScale; // (1 << 24) / range
218 : };
219 : Rec* fRecs;
220 :
221 : void commonAsAGradient(GradientInfo*, bool flipGrad = false) const;
222 :
223 : bool onAsLuminanceColor(SkColor*) const override;
224 :
225 :
226 : void initLinearBitmap(SkBitmap* bitmap) const;
227 :
228 : /*
229 : * Takes in pointers to gradient color and Rec info as colorSrc and recSrc respectively.
230 : * Count is the number of colors in the gradient
231 : * It will then flip all the color and rec information and return in their respective Dst
232 : * pointers. It is assumed that space has already been allocated for the Dst pointers.
233 : * The rec src and dst are only assumed to be valid if count > 2
234 : */
235 : static void FlipGradientColors(SkColor* colorDst, Rec* recDst,
236 : SkColor* colorSrc, Rec* recSrc,
237 : int count);
238 :
239 : template <typename T, typename... Args>
240 25 : static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
241 25 : auto* ctx = alloc->make<T>(std::forward<Args>(args)...);
242 25 : if (!ctx->isValid()) {
243 0 : return nullptr;
244 : }
245 25 : return ctx;
246 : }
247 :
248 : private:
249 : enum {
250 : kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
251 :
252 : kStorageSize = kColorStorageCount *
253 : (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec) + sizeof(SkColor4f))
254 : };
255 : SkColor fStorage[(kStorageSize + 3) >> 2];
256 : public:
257 : SkColor* fOrigColors; // original colors, before modulation by paint in context.
258 : SkColor4f* fOrigColors4f; // original colors, as linear floats
259 : SkScalar* fOrigPos; // original positions
260 : int fColorCount;
261 : sk_sp<SkColorSpace> fColorSpace; // color space of gradient stops
262 :
263 25 : bool colorsAreOpaque() const { return fColorsAreOpaque; }
264 :
265 0 : TileMode getTileMode() const { return fTileMode; }
266 0 : Rec* getRecs() const { return fRecs; }
267 :
268 : private:
269 : bool fColorsAreOpaque;
270 :
271 : sk_sp<GradientShaderCache> refCache(U8CPU alpha, bool dither) const;
272 : mutable SkMutex fCacheMutex;
273 : mutable sk_sp<GradientShaderCache> fCache;
274 :
275 : void initCommon();
276 :
277 : typedef SkShader INHERITED;
278 : };
279 :
280 2816 : static inline int init_dither_toggle(int x, int y) {
281 2816 : x &= 1;
282 2816 : y = (y & 1) << 1;
283 2816 : return (x | y) * SkGradientShaderBase::kDitherStride32;
284 : }
285 :
286 0 : static inline int next_dither_toggle(int toggle) {
287 0 : return toggle ^ SkGradientShaderBase::kDitherStride32;
288 : }
289 :
290 : ///////////////////////////////////////////////////////////////////////////////
291 :
292 : #if SK_SUPPORT_GPU
293 :
294 : #include "GrColorSpaceXform.h"
295 : #include "GrCoordTransform.h"
296 : #include "GrFragmentProcessor.h"
297 : #include "glsl/GrGLSLColorSpaceXformHelper.h"
298 : #include "glsl/GrGLSLFragmentProcessor.h"
299 : #include "glsl/GrGLSLProgramDataManager.h"
300 :
301 : class GrInvariantOutput;
302 :
303 : /*
304 : * The interpretation of the texture matrix depends on the sample mode. The
305 : * texture matrix is applied both when the texture coordinates are explicit
306 : * and when vertex positions are used as texture coordinates. In the latter
307 : * case the texture matrix is applied to the pre-view-matrix position
308 : * values.
309 : *
310 : * Normal SampleMode
311 : * The post-matrix texture coordinates are in normalize space with (0,0) at
312 : * the top-left and (1,1) at the bottom right.
313 : * RadialGradient
314 : * The matrix specifies the radial gradient parameters.
315 : * (0,0) in the post-matrix space is center of the radial gradient.
316 : * Radial2Gradient
317 : * Matrix transforms to space where first circle is centered at the
318 : * origin. The second circle will be centered (x, 0) where x may be
319 : * 0 and is provided by setRadial2Params. The post-matrix space is
320 : * normalized such that 1 is the second radius - first radius.
321 : * SweepGradient
322 : * The angle from the origin of texture coordinates in post-matrix space
323 : * determines the gradient value.
324 : */
325 :
326 : class GrTextureStripAtlas;
327 :
328 : // Base class for Gr gradient effects
329 : class GrGradientEffect : public GrFragmentProcessor {
330 : public:
331 0 : struct CreateArgs {
332 0 : CreateArgs(GrContext* context,
333 : const SkGradientShaderBase* shader,
334 : const SkMatrix* matrix,
335 : SkShader::TileMode tileMode,
336 : sk_sp<GrColorSpaceXform> colorSpaceXform,
337 : bool gammaCorrect)
338 0 : : fContext(context)
339 : , fShader(shader)
340 : , fMatrix(matrix)
341 : , fTileMode(tileMode)
342 0 : , fColorSpaceXform(std::move(colorSpaceXform))
343 0 : , fGammaCorrect(gammaCorrect) {}
344 :
345 : GrContext* fContext;
346 : const SkGradientShaderBase* fShader;
347 : const SkMatrix* fMatrix;
348 : SkShader::TileMode fTileMode;
349 : sk_sp<GrColorSpaceXform> fColorSpaceXform;
350 : bool fGammaCorrect;
351 : };
352 :
353 : class GLSLProcessor;
354 :
355 : ~GrGradientEffect() override;
356 :
357 0 : bool useAtlas() const { return SkToBool(-1 != fRow); }
358 0 : SkScalar getYCoord() const { return fYCoord; }
359 :
360 : enum ColorType {
361 : kTwo_ColorType,
362 : kThree_ColorType, // Symmetric three color
363 : kTexture_ColorType,
364 :
365 : #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
366 : kSingleHardStop_ColorType, // 0, t, t, 1
367 : kHardStopLeftEdged_ColorType, // 0, 0, 1
368 : kHardStopRightEdged_ColorType, // 0, 1, 1
369 : #endif
370 : };
371 :
372 0 : ColorType getColorType() const { return fColorType; }
373 :
374 : // Determines the type of gradient, one of:
375 : // - Two-color
376 : // - Symmetric three-color
377 : // - Texture
378 : // - Centered hard stop
379 : // - Left-edged hard stop
380 : // - Right-edged hard stop
381 : ColorType determineColorType(const SkGradientShaderBase& shader);
382 :
383 : enum PremulType {
384 : kBeforeInterp_PremulType,
385 : kAfterInterp_PremulType,
386 : };
387 :
388 0 : PremulType getPremulType() const { return fPremulType; }
389 :
390 0 : const SkColor* getColors(int pos) const {
391 0 : SkASSERT(fColorType != kTexture_ColorType);
392 0 : SkASSERT(pos < fColors.count());
393 0 : return &fColors[pos];
394 : }
395 :
396 0 : const SkColor4f* getColors4f(int pos) const {
397 0 : SkASSERT(fColorType != kTexture_ColorType);
398 0 : SkASSERT(pos < fColors4f.count());
399 0 : return &fColors4f[pos];
400 : }
401 :
402 : protected:
403 : GrGradientEffect(const CreateArgs&, bool isOpaque);
404 :
405 : #if GR_TEST_UTILS
406 : /** Helper struct that stores (and populates) parameters to construct a random gradient.
407 : If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and
408 : fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount
409 : will be the number of color stops in either case, and fColors and fStops can be passed to
410 : the gradient factory. (The constructor may decide not to use stops, in which case fStops
411 : will be nullptr). */
412 0 : struct RandomGradientParams {
413 : static const int kMaxRandomGradientColors = 5;
414 :
415 : RandomGradientParams(SkRandom* r);
416 :
417 : bool fUseColors4f;
418 : SkColor fColors[kMaxRandomGradientColors];
419 : SkColor4f fColors4f[kMaxRandomGradientColors];
420 : sk_sp<SkColorSpace> fColorSpace;
421 : SkScalar fStopStorage[kMaxRandomGradientColors];
422 : SkShader::TileMode fTileMode;
423 : int fColorCount;
424 : SkScalar* fStops;
425 : };
426 : #endif
427 :
428 : bool onIsEqual(const GrFragmentProcessor&) const override;
429 :
430 0 : const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
431 :
432 : private:
433 : static OptimizationFlags OptFlags(bool isOpaque);
434 :
435 : // If we're in legacy mode, then fColors will be populated. If we're gamma-correct, then
436 : // fColors4f and fColorSpaceXform will be populated.
437 : SkTDArray<SkColor> fColors;
438 :
439 : SkTDArray<SkColor4f> fColors4f;
440 : sk_sp<GrColorSpaceXform> fColorSpaceXform;
441 :
442 : SkTDArray<SkScalar> fPositions;
443 : SkShader::TileMode fTileMode;
444 :
445 : GrCoordTransform fCoordTransform;
446 : TextureSampler fTextureSampler;
447 : SkScalar fYCoord;
448 : GrTextureStripAtlas* fAtlas;
449 : int fRow;
450 : bool fIsOpaque;
451 : ColorType fColorType;
452 : PremulType fPremulType; // This is already baked into the table for texture gradients, and
453 : // only changes behavior for gradients that don't use a texture.
454 : typedef GrFragmentProcessor INHERITED;
455 :
456 : };
457 :
458 : ///////////////////////////////////////////////////////////////////////////////
459 :
460 : // Base class for GL gradient effects
461 0 : class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
462 : public:
463 0 : GLSLProcessor() {
464 0 : fCachedYCoord = SK_ScalarMax;
465 0 : }
466 :
467 : protected:
468 : void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
469 :
470 : protected:
471 : /**
472 : * Subclasses must call this. It will return a key for the part of the shader code controlled
473 : * by the base class. The subclasses must stick it in their key and then pass it to the below
474 : * emit* functions from their emitCode function.
475 : */
476 : static uint32_t GenBaseGradientKey(const GrProcessor&);
477 :
478 : // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
479 : // should call this method from their emitCode().
480 : void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
481 :
482 : // Emit code that gets a fragment's color from an expression for t; has branches for
483 : // several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+
484 : // color gradients that use the traditional texture lookup, as well as several varieties
485 : // of hard stop gradients
486 : void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
487 : GrGLSLUniformHandler* uniformHandler,
488 : const GrShaderCaps* shaderCaps,
489 : const GrGradientEffect&,
490 : const char* gradientTValue,
491 : const char* outputColor,
492 : const char* inputColor,
493 : const TextureSamplers&);
494 :
495 : private:
496 : enum {
497 : // First bit for premul before/after interp
498 : kPremulBeforeInterpKey = 1,
499 :
500 : // Next three bits for 2/3 color type or different special
501 : // hard stop cases (neither means using texture atlas)
502 : kTwoColorKey = 2,
503 : kThreeColorKey = 4,
504 : #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
505 : kHardStopCenteredKey = 6,
506 : kHardStopZeroZeroOneKey = 8,
507 : kHardStopZeroOneOneKey = 10,
508 :
509 : // Next two bits for tile mode
510 : kClampTileMode = 16,
511 : kRepeatTileMode = 32,
512 : kMirrorTileMode = 48,
513 :
514 : // Lower six bits for premul, 2/3 color type, and tile mode
515 : kReservedBits = 6,
516 : #endif
517 : };
518 :
519 : SkScalar fCachedYCoord;
520 : GrGLSLProgramDataManager::UniformHandle fColorsUni;
521 : GrGLSLProgramDataManager::UniformHandle fHardStopT;
522 : GrGLSLProgramDataManager::UniformHandle fFSYUni;
523 : GrGLSLColorSpaceXformHelper fColorSpaceHelper;
524 :
525 : typedef GrGLSLFragmentProcessor INHERITED;
526 : };
527 :
528 : #endif
529 :
530 : #endif
|