aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/shaders/gradients/SkGradientShaderPriv.h
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2017-05-25 15:29:13 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-05-25 20:05:08 +0000
commitfabe0b26d05624ce7374f6ca89bd66df6142534e (patch)
treef32b5873b31185d7e86e6c48fbdbd654efb8af7a /src/shaders/gradients/SkGradientShaderPriv.h
parent1c214313248a4b5a69af14539608c54fb67c2bf8 (diff)
Relocate shaders to own dir
Consolidate all shader impls under src/shaders/. Change-Id: I450e37541214704c1ad9e379d9d753b7cc62fac3 Reviewed-on: https://skia-review.googlesource.com/17927 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Herb Derby <herb@google.com>
Diffstat (limited to 'src/shaders/gradients/SkGradientShaderPriv.h')
-rw-r--r--src/shaders/gradients/SkGradientShaderPriv.h540
1 files changed, 540 insertions, 0 deletions
diff --git a/src/shaders/gradients/SkGradientShaderPriv.h b/src/shaders/gradients/SkGradientShaderPriv.h
new file mode 100644
index 0000000000..7a66edaffc
--- /dev/null
+++ b/src/shaders/gradients/SkGradientShaderPriv.h
@@ -0,0 +1,540 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkGradientShaderPriv_DEFINED
+#define SkGradientShaderPriv_DEFINED
+
+#include "SkGradientBitmapCache.h"
+#include "SkGradientShader.h"
+
+#include "SkArenaAlloc.h"
+#include "SkAutoMalloc.h"
+#include "SkClampRange.h"
+#include "SkColorPriv.h"
+#include "SkColorSpace.h"
+#include "SkOnce.h"
+#include "SkPM4fPriv.h"
+#include "SkRasterPipeline.h"
+#include "SkReadBuffer.h"
+#include "SkShaderBase.h"
+#include "SkUtils.h"
+#include "SkWriteBuffer.h"
+
+#if SK_SUPPORT_GPU
+ #define GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1
+#endif
+
+static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
+ int count) {
+ if (count > 0) {
+ if (v0 == v1) {
+ sk_memset32(dst, v0, count);
+ } else {
+ int pairs = count >> 1;
+ for (int i = 0; i < pairs; i++) {
+ *dst++ = v0;
+ *dst++ = v1;
+ }
+ if (count & 1) {
+ *dst = v0;
+ }
+ }
+ }
+}
+
+// Clamp
+
+static inline SkFixed clamp_tileproc(SkFixed x) {
+ return SkClampMax(x, 0xFFFF);
+}
+
+// Repeat
+
+static inline SkFixed repeat_tileproc(SkFixed x) {
+ return x & 0xFFFF;
+}
+
+// Mirror
+
+static inline SkFixed mirror_tileproc(SkFixed x) {
+ int s = SkLeftShift(x, 15) >> 31;
+ return (x ^ s) & 0xFFFF;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+typedef SkFixed (*TileProc)(SkFixed);
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const TileProc gTileProcs[] = {
+ clamp_tileproc,
+ repeat_tileproc,
+ mirror_tileproc
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SkGradientShaderBase : public SkShaderBase {
+public:
+ struct Descriptor {
+ Descriptor() {
+ sk_bzero(this, sizeof(*this));
+ fTileMode = SkShader::kClamp_TileMode;
+ }
+
+ const SkMatrix* fLocalMatrix;
+ const SkColor4f* fColors;
+ sk_sp<SkColorSpace> fColorSpace;
+ const SkScalar* fPos;
+ int fCount;
+ SkShader::TileMode fTileMode;
+ uint32_t fGradFlags;
+
+ void flatten(SkWriteBuffer&) const;
+ };
+
+ class DescriptorScope : public Descriptor {
+ public:
+ DescriptorScope() {}
+
+ bool unflatten(SkReadBuffer&);
+
+ // fColors and fPos always point into local memory, so they can be safely mutated
+ //
+ SkColor4f* mutableColors() { return const_cast<SkColor4f*>(fColors); }
+ SkScalar* mutablePos() { return const_cast<SkScalar*>(fPos); }
+
+ private:
+ enum {
+ kStorageCount = 16
+ };
+ SkColor4f fColorStorage[kStorageCount];
+ SkScalar fPosStorage[kStorageCount];
+ SkMatrix fLocalMatrixStorage;
+ SkAutoMalloc fDynamicStorage;
+ };
+
+ SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit);
+ ~SkGradientShaderBase() override;
+
+ // The cache is initialized on-demand when getCache32 is called.
+ class GradientShaderCache : public SkRefCnt {
+ public:
+ GradientShaderCache(U8CPU alpha, bool dither, const SkGradientShaderBase& shader);
+ ~GradientShaderCache();
+
+ const SkPMColor* getCache32();
+
+ SkPixelRef* getCache32PixelRef() const { return fCache32PixelRef.get(); }
+
+ unsigned getAlpha() const { return fCacheAlpha; }
+ bool getDither() const { return fCacheDither; }
+
+ private:
+ // Working pointer. If it's nullptr, we need to recompute the cache values.
+ SkPMColor* fCache32;
+
+ sk_sp<SkPixelRef> fCache32PixelRef;
+ const unsigned fCacheAlpha; // The alpha value we used when we computed the cache.
+ // Larger than 8bits so we can store uninitialized
+ // value.
+ const bool fCacheDither; // The dither flag used when we computed the cache.
+
+ const SkGradientShaderBase& fShader;
+
+ // Make sure we only initialize the cache once.
+ SkOnce fCache32InitOnce;
+
+ static void initCache32(GradientShaderCache* cache);
+
+ static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
+ U8CPU alpha, uint32_t gradFlags, bool dither);
+ };
+
+ class GradientShaderBaseContext : public Context {
+ public:
+ GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&);
+
+ uint32_t getFlags() const override { return fFlags; }
+
+ bool isValid() const;
+
+ protected:
+ SkMatrix fDstToIndex;
+ SkMatrix::MapXYProc fDstToIndexProc;
+ uint8_t fDstToIndexClass;
+ uint8_t fFlags;
+ bool fDither;
+
+ sk_sp<GradientShaderCache> fCache;
+
+ private:
+ typedef Context INHERITED;
+ };
+
+ bool isOpaque() const override;
+
+ enum class GradientBitmapType : uint8_t {
+ kLegacy,
+ kSRGB,
+ kHalfFloat,
+ };
+
+ void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const;
+
+ enum {
+ /// Seems like enough for visual accuracy. TODO: if pos[] deserves
+ /// it, use a larger cache.
+ kCache32Bits = 8,
+ kCache32Count = (1 << kCache32Bits),
+ kCache32Shift = 16 - kCache32Bits,
+ kSqrt32Shift = 8 - kCache32Bits,
+
+ /// This value is used to *read* the dither cache; it may be 0
+ /// if dithering is disabled.
+ kDitherStride32 = kCache32Count,
+ };
+
+ uint32_t getGradFlags() const { return fGradFlags; }
+
+protected:
+ struct Rec {
+ SkFixed fPos; // 0...1
+ uint32_t fScale; // (1 << 24) / range
+ };
+
+ class GradientShaderBase4fContext;
+
+ SkGradientShaderBase(SkReadBuffer& );
+ void flatten(SkWriteBuffer&) const override;
+ SK_TO_STRING_OVERRIDE()
+
+ void commonAsAGradient(GradientInfo*, bool flipGrad = false) const;
+
+ bool onAsLuminanceColor(SkColor*) const override;
+
+ void initLinearBitmap(SkBitmap* bitmap) const;
+
+ /*
+ * Takes in pointers to gradient color and Rec info as colorSrc and recSrc respectively.
+ * Count is the number of colors in the gradient
+ * It will then flip all the color and rec information and return in their respective Dst
+ * pointers. It is assumed that space has already been allocated for the Dst pointers.
+ * The rec src and dst are only assumed to be valid if count > 2
+ */
+ static void FlipGradientColors(SkColor* colorDst, Rec* recDst,
+ SkColor* colorSrc, Rec* recSrc,
+ int count);
+
+ bool onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* dstCS, SkArenaAlloc* alloc,
+ const SkMatrix& ctm, const SkPaint& paint,
+ const SkMatrix* localM) const override;
+
+ virtual bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
+ SkMatrix* matrix,
+ SkRasterPipeline* p) const { return false; }
+
+ template <typename T, typename... Args>
+ static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
+ auto* ctx = alloc->make<T>(std::forward<Args>(args)...);
+ if (!ctx->isValid()) {
+ return nullptr;
+ }
+ return ctx;
+ }
+
+ const SkMatrix fPtsToUnit;
+ TileMode fTileMode;
+ TileProc fTileProc;
+ uint8_t fGradFlags;
+ Rec* fRecs;
+
+private:
+ enum {
+ kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
+
+ kStorageSize = kColorStorageCount *
+ (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec) + sizeof(SkColor4f))
+ };
+ SkColor fStorage[(kStorageSize + 3) >> 2];
+public:
+ SkColor* fOrigColors; // original colors, before modulation by paint in context.
+ SkColor4f* fOrigColors4f; // original colors, as linear floats
+ SkScalar* fOrigPos; // original positions
+ int fColorCount;
+ sk_sp<SkColorSpace> fColorSpace; // color space of gradient stops
+
+ bool colorsAreOpaque() const { return fColorsAreOpaque; }
+
+ TileMode getTileMode() const { return fTileMode; }
+ Rec* getRecs() const { return fRecs; }
+
+private:
+ bool fColorsAreOpaque;
+
+ sk_sp<GradientShaderCache> refCache(U8CPU alpha, bool dither) const;
+ mutable SkMutex fCacheMutex;
+ mutable sk_sp<GradientShaderCache> fCache;
+
+ void initCommon();
+
+ typedef SkShaderBase INHERITED;
+};
+
+
+static inline int init_dither_toggle(int x, int y) {
+ x &= 1;
+ y = (y & 1) << 1;
+ return (x | y) * SkGradientShaderBase::kDitherStride32;
+}
+
+static inline int next_dither_toggle(int toggle) {
+ return toggle ^ SkGradientShaderBase::kDitherStride32;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#if SK_SUPPORT_GPU
+
+#include "GrColorSpaceXform.h"
+#include "GrCoordTransform.h"
+#include "GrFragmentProcessor.h"
+#include "glsl/GrGLSLColorSpaceXformHelper.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLProgramDataManager.h"
+
+class GrInvariantOutput;
+
+/*
+ * The interpretation of the texture matrix depends on the sample mode. The
+ * texture matrix is applied both when the texture coordinates are explicit
+ * and when vertex positions are used as texture coordinates. In the latter
+ * case the texture matrix is applied to the pre-view-matrix position
+ * values.
+ *
+ * Normal SampleMode
+ * The post-matrix texture coordinates are in normalize space with (0,0) at
+ * the top-left and (1,1) at the bottom right.
+ * RadialGradient
+ * The matrix specifies the radial gradient parameters.
+ * (0,0) in the post-matrix space is center of the radial gradient.
+ * Radial2Gradient
+ * Matrix transforms to space where first circle is centered at the
+ * origin. The second circle will be centered (x, 0) where x may be
+ * 0 and is provided by setRadial2Params. The post-matrix space is
+ * normalized such that 1 is the second radius - first radius.
+ * SweepGradient
+ * The angle from the origin of texture coordinates in post-matrix space
+ * determines the gradient value.
+ */
+
+ class GrTextureStripAtlas;
+
+// Base class for Gr gradient effects
+class GrGradientEffect : public GrFragmentProcessor {
+public:
+ struct CreateArgs {
+ CreateArgs(GrContext* context,
+ const SkGradientShaderBase* shader,
+ const SkMatrix* matrix,
+ SkShader::TileMode tileMode,
+ sk_sp<GrColorSpaceXform> colorSpaceXform,
+ bool gammaCorrect)
+ : fContext(context)
+ , fShader(shader)
+ , fMatrix(matrix)
+ , fTileMode(tileMode)
+ , fColorSpaceXform(std::move(colorSpaceXform))
+ , fGammaCorrect(gammaCorrect) {}
+
+ GrContext* fContext;
+ const SkGradientShaderBase* fShader;
+ const SkMatrix* fMatrix;
+ SkShader::TileMode fTileMode;
+ sk_sp<GrColorSpaceXform> fColorSpaceXform;
+ bool fGammaCorrect;
+ };
+
+ class GLSLProcessor;
+
+ ~GrGradientEffect() override;
+
+ bool useAtlas() const { return SkToBool(-1 != fRow); }
+ SkScalar getYCoord() const { return fYCoord; }
+
+ enum ColorType {
+ kTwo_ColorType,
+ kThree_ColorType, // Symmetric three color
+ kTexture_ColorType,
+
+#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
+ kSingleHardStop_ColorType, // 0, t, t, 1
+ kHardStopLeftEdged_ColorType, // 0, 0, 1
+ kHardStopRightEdged_ColorType, // 0, 1, 1
+#endif
+ };
+
+ ColorType getColorType() const { return fColorType; }
+
+ // Determines the type of gradient, one of:
+ // - Two-color
+ // - Symmetric three-color
+ // - Texture
+ // - Centered hard stop
+ // - Left-edged hard stop
+ // - Right-edged hard stop
+ ColorType determineColorType(const SkGradientShaderBase& shader);
+
+ enum PremulType {
+ kBeforeInterp_PremulType,
+ kAfterInterp_PremulType,
+ };
+
+ PremulType getPremulType() const { return fPremulType; }
+
+ const SkColor* getColors(int pos) const {
+ SkASSERT(fColorType != kTexture_ColorType);
+ SkASSERT(pos < fColors.count());
+ return &fColors[pos];
+ }
+
+ const SkColor4f* getColors4f(int pos) const {
+ SkASSERT(fColorType != kTexture_ColorType);
+ SkASSERT(pos < fColors4f.count());
+ return &fColors4f[pos];
+ }
+
+protected:
+ GrGradientEffect(const CreateArgs&, bool isOpaque);
+
+ #if GR_TEST_UTILS
+ /** Helper struct that stores (and populates) parameters to construct a random gradient.
+ If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and
+ fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount
+ will be the number of color stops in either case, and fColors and fStops can be passed to
+ the gradient factory. (The constructor may decide not to use stops, in which case fStops
+ will be nullptr). */
+ struct RandomGradientParams {
+ static const int kMaxRandomGradientColors = 5;
+
+ RandomGradientParams(SkRandom* r);
+
+ bool fUseColors4f;
+ SkColor fColors[kMaxRandomGradientColors];
+ SkColor4f fColors4f[kMaxRandomGradientColors];
+ sk_sp<SkColorSpace> fColorSpace;
+ SkScalar fStopStorage[kMaxRandomGradientColors];
+ SkShader::TileMode fTileMode;
+ int fColorCount;
+ SkScalar* fStops;
+ };
+ #endif
+
+ bool onIsEqual(const GrFragmentProcessor&) const override;
+
+ const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
+
+private:
+ static OptimizationFlags OptFlags(bool isOpaque);
+
+ // If we're in legacy mode, then fColors will be populated. If we're gamma-correct, then
+ // fColors4f and fColorSpaceXform will be populated.
+ SkTDArray<SkColor> fColors;
+
+ SkTDArray<SkColor4f> fColors4f;
+ sk_sp<GrColorSpaceXform> fColorSpaceXform;
+
+ SkTDArray<SkScalar> fPositions;
+ SkShader::TileMode fTileMode;
+
+ GrCoordTransform fCoordTransform;
+ TextureSampler fTextureSampler;
+ SkScalar fYCoord;
+ GrTextureStripAtlas* fAtlas;
+ int fRow;
+ bool fIsOpaque;
+ ColorType fColorType;
+ PremulType fPremulType; // This is already baked into the table for texture gradients, and
+ // only changes behavior for gradients that don't use a texture.
+ typedef GrFragmentProcessor INHERITED;
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+// Base class for GL gradient effects
+class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
+public:
+ GLSLProcessor() {
+ fCachedYCoord = SK_ScalarMax;
+ }
+
+protected:
+ void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
+
+protected:
+ /**
+ * Subclasses must call this. It will return a key for the part of the shader code controlled
+ * by the base class. The subclasses must stick it in their key and then pass it to the below
+ * emit* functions from their emitCode function.
+ */
+ static uint32_t GenBaseGradientKey(const GrProcessor&);
+
+ // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
+ // should call this method from their emitCode().
+ void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
+
+ // Emit code that gets a fragment's color from an expression for t; has branches for
+ // several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+
+ // color gradients that use the traditional texture lookup, as well as several varieties
+ // of hard stop gradients
+ void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
+ GrGLSLUniformHandler* uniformHandler,
+ const GrShaderCaps* shaderCaps,
+ const GrGradientEffect&,
+ const char* gradientTValue,
+ const char* outputColor,
+ const char* inputColor,
+ const TextureSamplers&);
+
+private:
+ enum {
+ // First bit for premul before/after interp
+ kPremulBeforeInterpKey = 1,
+
+ // Next three bits for 2/3 color type or different special
+ // hard stop cases (neither means using texture atlas)
+ kTwoColorKey = 2,
+ kThreeColorKey = 4,
+#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
+ kHardStopCenteredKey = 6,
+ kHardStopZeroZeroOneKey = 8,
+ kHardStopZeroOneOneKey = 10,
+
+ // Next two bits for tile mode
+ kClampTileMode = 16,
+ kRepeatTileMode = 32,
+ kMirrorTileMode = 48,
+
+ // Lower six bits for premul, 2/3 color type, and tile mode
+ kReservedBits = 6,
+#endif
+ };
+
+ SkScalar fCachedYCoord;
+ GrGLSLProgramDataManager::UniformHandle fColorsUni;
+ GrGLSLProgramDataManager::UniformHandle fHardStopT;
+ GrGLSLProgramDataManager::UniformHandle fFSYUni;
+ GrGLSLColorSpaceXformHelper fColorSpaceHelper;
+
+ typedef GrGLSLFragmentProcessor INHERITED;
+};
+
+#endif
+
+#endif