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