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 "SkGradientShader.h" 12 13 #include "SkArenaAlloc.h" 14 #include "SkAutoMalloc.h" 15 #include "SkMatrix.h" 16 #include "SkShaderBase.h" 17 #include "SkTArray.h" 18 #include "SkTemplates.h" 19 20 class SkColorSpace; 21 class SkColorSpaceXformer; 22 class SkRasterPipeline; 23 class SkReadBuffer; 24 class SkWriteBuffer; 25 26 class SkGradientShaderBase : public SkShaderBase { 27 public: 28 struct Descriptor { DescriptorDescriptor29 Descriptor() { 30 sk_bzero(this, sizeof(*this)); 31 fTileMode = SkShader::kClamp_TileMode; 32 } 33 34 const SkMatrix* fLocalMatrix; 35 const SkColor4f* fColors; 36 sk_sp<SkColorSpace> fColorSpace; 37 const SkScalar* fPos; 38 int fCount; 39 SkShader::TileMode fTileMode; 40 uint32_t fGradFlags; 41 42 void flatten(SkWriteBuffer&) const; 43 }; 44 45 class DescriptorScope : public Descriptor { 46 public: DescriptorScope()47 DescriptorScope() {} 48 49 bool unflatten(SkReadBuffer&); 50 51 // fColors and fPos always point into local memory, so they can be safely mutated 52 // mutableColors()53 SkColor4f* mutableColors() { return const_cast<SkColor4f*>(fColors); } mutablePos()54 SkScalar* mutablePos() { return const_cast<SkScalar*>(fPos); } 55 56 private: 57 enum { 58 kStorageCount = 16 59 }; 60 SkColor4f fColorStorage[kStorageCount]; 61 SkScalar fPosStorage[kStorageCount]; 62 SkMatrix fLocalMatrixStorage; 63 SkAutoMalloc fDynamicStorage; 64 }; 65 66 SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit); 67 ~SkGradientShaderBase() override; 68 69 bool isOpaque() const override; 70 71 enum class GradientBitmapType : uint8_t { 72 kLegacy, 73 kSRGB, 74 kHalfFloat, 75 }; 76 77 void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const; 78 getGradFlags()79 uint32_t getGradFlags() const { return fGradFlags; } 80 81 SkColor4f getXformedColor(size_t index, SkColorSpace*) const; 82 83 protected: 84 class GradientShaderBase4fContext; 85 86 SkGradientShaderBase(SkReadBuffer& ); 87 void flatten(SkWriteBuffer&) const override; 88 SK_TO_STRING_OVERRIDE() 89 90 void commonAsAGradient(GradientInfo*) const; 91 92 bool onAsLuminanceColor(SkColor*) const override; 93 94 void initLinearBitmap(SkBitmap* bitmap, GradientBitmapType) const; 95 96 bool onAppendStages(const StageRec&) const override; 97 bool onIsRasterPipelineOnly(const SkMatrix& ctm) const override; 98 99 virtual void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline, 100 SkRasterPipeline* postPipeline) const = 0; 101 102 template <typename T, typename... Args> CheckedMakeContext(SkArenaAlloc * alloc,Args &&...args)103 static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) { 104 auto* ctx = alloc->make<T>(std::forward<Args>(args)...); 105 if (!ctx->isValid()) { 106 return nullptr; 107 } 108 return ctx; 109 } 110 111 struct AutoXformColors { 112 AutoXformColors(const SkGradientShaderBase&, SkColorSpaceXformer*); 113 114 SkAutoSTMalloc<8, SkColor> fColors; 115 }; 116 117 const SkMatrix fPtsToUnit; 118 TileMode fTileMode; 119 uint8_t fGradFlags; 120 121 public: getPos(int i)122 SkScalar getPos(int i) const { 123 SkASSERT(i < fColorCount); 124 return fOrigPos ? fOrigPos[i] : SkIntToScalar(i) / (fColorCount - 1); 125 } 126 getLegacyColor(int i)127 SkColor getLegacyColor(int i) const { 128 SkASSERT(i < fColorCount); 129 return fOrigColors4f[i].toSkColor(); 130 } 131 132 SkColor4f* fOrigColors4f; // original colors, as linear floats 133 SkScalar* fOrigPos; // original positions 134 int fColorCount; 135 sk_sp<SkColorSpace> fColorSpace; // color space of gradient stops 136 colorsAreOpaque()137 bool colorsAreOpaque() const { return fColorsAreOpaque; } 138 getTileMode()139 TileMode getTileMode() const { return fTileMode; } 140 141 private: 142 // Reserve inline space for up to 4 stops. 143 static constexpr size_t kInlineStopCount = 4; 144 static constexpr size_t kInlineStorageSize = (sizeof(SkColor4f) + sizeof(SkScalar)) 145 * kInlineStopCount; 146 SkAutoSTMalloc<kInlineStorageSize, uint8_t> fStorage; 147 148 bool fColorsAreOpaque; 149 150 typedef SkShaderBase INHERITED; 151 }; 152 153 /////////////////////////////////////////////////////////////////////////////// 154 155 #if SK_SUPPORT_GPU 156 157 #include "GrColorSpaceInfo.h" 158 #include "GrCoordTransform.h" 159 #include "GrFragmentProcessor.h" 160 #include "glsl/GrGLSLFragmentProcessor.h" 161 #include "glsl/GrGLSLProgramDataManager.h" 162 163 class GrInvariantOutput; 164 165 /* 166 * The interpretation of the texture matrix depends on the sample mode. The 167 * texture matrix is applied both when the texture coordinates are explicit 168 * and when vertex positions are used as texture coordinates. In the latter 169 * case the texture matrix is applied to the pre-view-matrix position 170 * values. 171 * 172 * Normal SampleMode 173 * The post-matrix texture coordinates are in normalize space with (0,0) at 174 * the top-left and (1,1) at the bottom right. 175 * RadialGradient 176 * The matrix specifies the radial gradient parameters. 177 * (0,0) in the post-matrix space is center of the radial gradient. 178 * Radial2Gradient 179 * Matrix transforms to space where first circle is centered at the 180 * origin. The second circle will be centered (x, 0) where x may be 181 * 0 and is provided by setRadial2Params. The post-matrix space is 182 * normalized such that 1 is the second radius - first radius. 183 * SweepGradient 184 * The angle from the origin of texture coordinates in post-matrix space 185 * determines the gradient value. 186 */ 187 188 class GrTextureStripAtlas; 189 190 // Base class for Gr gradient effects 191 class GrGradientEffect : public GrFragmentProcessor { 192 public: 193 struct CreateArgs { CreateArgsCreateArgs194 CreateArgs(GrContext* context, 195 const SkGradientShaderBase* shader, 196 const SkMatrix* matrix, 197 SkShader::TileMode tileMode, 198 SkColorSpace* dstColorSpace) 199 : fContext(context) 200 , fShader(shader) 201 , fMatrix(matrix) 202 , fDstColorSpace(dstColorSpace) { 203 switch (tileMode) { 204 case SkShader::kClamp_TileMode: 205 fWrapMode = GrSamplerState::WrapMode::kClamp; 206 break; 207 case SkShader::kRepeat_TileMode: 208 fWrapMode = GrSamplerState::WrapMode::kRepeat; 209 break; 210 case SkShader::kMirror_TileMode: 211 fWrapMode = GrSamplerState::WrapMode::kMirrorRepeat; 212 break; 213 case SkShader::kDecal_TileMode: 214 // TODO: actually support decal 215 fWrapMode = GrSamplerState::WrapMode::kClamp; 216 break; 217 } 218 } 219 CreateArgsCreateArgs220 CreateArgs(GrContext* context, 221 const SkGradientShaderBase* shader, 222 const SkMatrix* matrix, 223 GrSamplerState::WrapMode wrapMode, 224 SkColorSpace* dstColorSpace) 225 : fContext(context) 226 , fShader(shader) 227 , fMatrix(matrix) 228 , fWrapMode(wrapMode) 229 , fDstColorSpace(dstColorSpace) {} 230 231 GrContext* fContext; 232 const SkGradientShaderBase* fShader; 233 const SkMatrix* fMatrix; 234 GrSamplerState::WrapMode fWrapMode; 235 SkColorSpace* fDstColorSpace; 236 }; 237 238 class GLSLProcessor; 239 240 ~GrGradientEffect() override; 241 useAtlas()242 bool useAtlas() const { return SkToBool(-1 != fRow); } 243 244 // Controls the implementation strategy for this effect. 245 // NB: all entries need to be reflected in the key. 246 enum class InterpolationStrategy : uint8_t { 247 kSingle, // interpolation in a single domain [0,1] 248 kThreshold, // interpolation in two domains [0,T) [T,1], with normal clamping 249 kThresholdClamp0, // same as kThreshold, but clamped only on the left edge 250 kThresholdClamp1, // same as kThreshold, but clamped only on the right edge 251 kTexture, // texture-based fallback 252 }; 253 254 enum PremulType { 255 kBeforeInterp_PremulType, 256 kAfterInterp_PremulType, 257 }; 258 259 protected: 260 GrGradientEffect(ClassID classID, const CreateArgs&, bool isOpaque); 261 explicit GrGradientEffect(const GrGradientEffect&); // facilitates clone() implementations 262 263 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 264 265 // Helper function used by derived class factories to handle color space transformation and 266 // modulation by input alpha. AdjustFP(std::unique_ptr<GrGradientEffect> gradientFP,const CreateArgs & args)267 static std::unique_ptr<GrFragmentProcessor> AdjustFP( 268 std::unique_ptr<GrGradientEffect> gradientFP, const CreateArgs& args) { 269 if (!gradientFP->isValid()) { 270 return nullptr; 271 } 272 std::unique_ptr<GrFragmentProcessor> fp; 273 // With analytic gradients, we pre-convert the stops to the destination color space, so no 274 // xform is needed. With texture-based gradients, we leave the data in the source color 275 // space (to avoid clamping if we can't use F16)... Add an extra FP to do the xform. 276 if (gradientFP->fStrategy == InterpolationStrategy::kTexture) { 277 // Our texture is always either F16 or sRGB, so the data is "linear" in the shader. 278 // Create our xform assuming float inputs, which will suppress any extra sRGB work. 279 // We do support having a transfer function on the color space of the stops, so 280 // this FP may include that transformation. 281 fp = GrColorSpaceXformEffect::Make(std::move(gradientFP), 282 args.fShader->fColorSpace.get(), 283 kRGBA_float_GrPixelConfig, 284 args.fDstColorSpace); 285 } else { 286 fp = std::move(gradientFP); 287 } 288 return GrFragmentProcessor::MulChildByInputAlpha(std::move(fp)); 289 } 290 291 #if GR_TEST_UTILS 292 /** Helper struct that stores (and populates) parameters to construct a random gradient. 293 If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and 294 fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount 295 will be the number of color stops in either case, and fColors and fStops can be passed to 296 the gradient factory. (The constructor may decide not to use stops, in which case fStops 297 will be nullptr). */ 298 struct RandomGradientParams { 299 static constexpr int kMaxRandomGradientColors = 5; 300 301 RandomGradientParams(SkRandom* r); 302 303 bool fUseColors4f; 304 SkColor fColors[kMaxRandomGradientColors]; 305 SkColor4f fColors4f[kMaxRandomGradientColors]; 306 sk_sp<SkColorSpace> fColorSpace; 307 SkScalar fStopStorage[kMaxRandomGradientColors]; 308 SkShader::TileMode fTileMode; 309 int fColorCount; 310 SkScalar* fStops; 311 }; 312 #endif 313 314 bool onIsEqual(const GrFragmentProcessor&) const override; 315 getCoordTransform()316 const GrCoordTransform& getCoordTransform() const { return fCoordTransform; } 317 318 /** Checks whether the constructor failed to fully initialize the processor. */ isValid()319 bool isValid() const { 320 return fStrategy != InterpolationStrategy::kTexture || fTextureSampler.isInitialized(); 321 } 322 323 private: 324 void addInterval(const SkGradientShaderBase&, size_t idx0, size_t idx1, SkColorSpace*); 325 326 static OptimizationFlags OptFlags(bool isOpaque); 327 328 // Interpolation intervals, encoded as 4f tuples of (scale, bias) 329 // such that color(t) = t * scale + bias. 330 SkSTArray<4, GrColor4f, true> fIntervals; 331 332 GrSamplerState::WrapMode fWrapMode; 333 334 GrCoordTransform fCoordTransform; 335 TextureSampler fTextureSampler; 336 SkScalar fYCoord; 337 GrTextureStripAtlas* fAtlas; 338 int fRow; 339 bool fIsOpaque; 340 341 InterpolationStrategy fStrategy; 342 SkScalar fThreshold; // used for InterpolationStrategy::kThreshold 343 PremulType fPremulType; // This is already baked into the table for texture 344 // gradients, and only changes behavior for gradients 345 // that don't use a texture. 346 347 typedef GrFragmentProcessor INHERITED; 348 349 }; 350 351 /////////////////////////////////////////////////////////////////////////////// 352 353 // Base class for GL gradient effects 354 class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor { 355 public: GLSLProcessor()356 GLSLProcessor() { 357 fCachedYCoord = SK_ScalarMax; 358 } 359 360 static uint32_t GenBaseGradientKey(const GrProcessor&); 361 362 protected: 363 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; 364 365 // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses 366 // should call this method from their emitCode(). 367 void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&); 368 369 // Emit code that gets a fragment's color from an expression for t; has branches for 370 // several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+ 371 // color gradients that use the traditional texture lookup, as well as several varieties 372 // of hard stop gradients 373 void emitColor(GrGLSLFPFragmentBuilder* fragBuilder, 374 GrGLSLUniformHandler* uniformHandler, 375 const GrShaderCaps* shaderCaps, 376 const GrGradientEffect&, 377 const char* gradientTValue, 378 const char* outputColor, 379 const char* inputColor, 380 const TextureSamplers&); 381 382 private: 383 void emitAnalyticalColor(GrGLSLFPFragmentBuilder* fragBuilder, 384 GrGLSLUniformHandler* uniformHandler, 385 const GrShaderCaps* shaderCaps, 386 const GrGradientEffect&, 387 const char* gradientTValue, 388 const char* outputColor, 389 const char* inputColor); 390 391 SkScalar fCachedYCoord; 392 GrGLSLProgramDataManager::UniformHandle fIntervalsUni; 393 GrGLSLProgramDataManager::UniformHandle fThresholdUni; 394 GrGLSLProgramDataManager::UniformHandle fFSYUni; 395 396 typedef GrGLSLFragmentProcessor INHERITED; 397 }; 398 399 #endif 400 401 #endif 402