1 2 /* 3 * Copyright 2012 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 #include "SkSweepGradient.h" 10 11 SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor& desc) 12 : SkGradientShaderBase(desc) 13 , fCenter(SkPoint::Make(cx, cy)) 14 { 15 fPtsToUnit.setTranslate(-cx, -cy); 16 17 // overwrite the tilemode to a canonical value (since sweep ignores it) 18 fTileMode = SkShader::kClamp_TileMode; 19 } 20 21 SkShader::BitmapType SkSweepGradient::asABitmap(SkBitmap* bitmap, 22 SkMatrix* matrix, SkShader::TileMode* xy) const { 23 if (bitmap) { 24 this->getGradientTableBitmap(bitmap); 25 } 26 if (matrix) { 27 *matrix = fPtsToUnit; 28 } 29 if (xy) { 30 xy[0] = fTileMode; 31 xy[1] = kClamp_TileMode; 32 } 33 return kSweep_BitmapType; 34 } 35 36 SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const { 37 if (info) { 38 commonAsAGradient(info); 39 info->fPoint[0] = fCenter; 40 } 41 return kSweep_GradientType; 42 } 43 44 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING 45 SkSweepGradient::SkSweepGradient(SkReadBuffer& buffer) 46 : INHERITED(buffer), 47 fCenter(buffer.readPoint()) { 48 } 49 #endif 50 51 SkFlattenable* SkSweepGradient::CreateProc(SkReadBuffer& buffer) { 52 DescriptorScope desc; 53 if (!desc.unflatten(buffer)) { 54 return NULL; 55 } 56 const SkPoint center = buffer.readPoint(); 57 return SkGradientShader::CreateSweep(center.x(), center.y(), desc.fColors, desc.fPos, 58 desc.fCount, desc.fGradFlags, desc.fLocalMatrix); 59 } 60 61 void SkSweepGradient::flatten(SkWriteBuffer& buffer) const { 62 this->INHERITED::flatten(buffer); 63 buffer.writePoint(fCenter); 64 } 65 66 size_t SkSweepGradient::contextSize() const { 67 return sizeof(SweepGradientContext); 68 } 69 70 SkShader::Context* SkSweepGradient::onCreateContext(const ContextRec& rec, void* storage) const { 71 return SkNEW_PLACEMENT_ARGS(storage, SweepGradientContext, (*this, rec)); 72 } 73 74 SkSweepGradient::SweepGradientContext::SweepGradientContext( 75 const SkSweepGradient& shader, const ContextRec& rec) 76 : INHERITED(shader, rec) {} 77 78 // returns angle in a circle [0..2PI) -> [0..255] 79 static unsigned SkATan2_255(float y, float x) { 80 // static const float g255Over2PI = 255 / (2 * SK_ScalarPI); 81 static const float g255Over2PI = 40.584510488433314f; 82 83 float result = sk_float_atan2(y, x); 84 if (result < 0) { 85 result += 2 * SK_ScalarPI; 86 } 87 SkASSERT(result >= 0); 88 // since our value is always >= 0, we can cast to int, which is faster than 89 // calling floorf() 90 int ir = (int)(result * g255Over2PI); 91 SkASSERT(ir >= 0 && ir <= 255); 92 return ir; 93 } 94 95 void SkSweepGradient::SweepGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, 96 int count) { 97 SkMatrix::MapXYProc proc = fDstToIndexProc; 98 const SkMatrix& matrix = fDstToIndex; 99 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); 100 int toggle = init_dither_toggle(x, y); 101 SkPoint srcPt; 102 103 if (fDstToIndexClass != kPerspective_MatrixClass) { 104 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, 105 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 106 SkScalar dx, fx = srcPt.fX; 107 SkScalar dy, fy = srcPt.fY; 108 109 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 110 SkFixed storage[2]; 111 (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf, 112 &storage[0], &storage[1]); 113 dx = SkFixedToScalar(storage[0]); 114 dy = SkFixedToScalar(storage[1]); 115 } else { 116 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 117 dx = matrix.getScaleX(); 118 dy = matrix.getSkewY(); 119 } 120 121 for (; count > 0; --count) { 122 *dstC++ = cache[toggle + SkATan2_255(fy, fx)]; 123 fx += dx; 124 fy += dy; 125 toggle = next_dither_toggle(toggle); 126 } 127 } else { // perspective case 128 for (int stop = x + count; x < stop; x++) { 129 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, 130 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 131 *dstC++ = cache[toggle + SkATan2_255(srcPt.fY, srcPt.fX)]; 132 toggle = next_dither_toggle(toggle); 133 } 134 } 135 } 136 137 void SkSweepGradient::SweepGradientContext::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, 138 int count) { 139 SkMatrix::MapXYProc proc = fDstToIndexProc; 140 const SkMatrix& matrix = fDstToIndex; 141 const uint16_t* SK_RESTRICT cache = fCache->getCache16(); 142 int toggle = init_dither_toggle16(x, y); 143 SkPoint srcPt; 144 145 if (fDstToIndexClass != kPerspective_MatrixClass) { 146 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, 147 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 148 SkScalar dx, fx = srcPt.fX; 149 SkScalar dy, fy = srcPt.fY; 150 151 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 152 SkFixed storage[2]; 153 (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf, 154 &storage[0], &storage[1]); 155 dx = SkFixedToScalar(storage[0]); 156 dy = SkFixedToScalar(storage[1]); 157 } else { 158 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 159 dx = matrix.getScaleX(); 160 dy = matrix.getSkewY(); 161 } 162 163 for (; count > 0; --count) { 164 int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits); 165 *dstC++ = cache[toggle + index]; 166 toggle = next_dither_toggle16(toggle); 167 fx += dx; 168 fy += dy; 169 } 170 } else { // perspective case 171 for (int stop = x + count; x < stop; x++) { 172 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, 173 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 174 175 int index = SkATan2_255(srcPt.fY, srcPt.fX); 176 index >>= (8 - kCache16Bits); 177 *dstC++ = cache[toggle + index]; 178 toggle = next_dither_toggle16(toggle); 179 } 180 } 181 } 182 183 ///////////////////////////////////////////////////////////////////// 184 185 #if SK_SUPPORT_GPU 186 187 #include "GrTBackendProcessorFactory.h" 188 #include "gl/builders/GrGLProgramBuilder.h" 189 #include "SkGr.h" 190 191 class GrGLSweepGradient : public GrGLGradientEffect { 192 public: 193 194 GrGLSweepGradient(const GrBackendProcessorFactory& factory, 195 const GrProcessor&) : INHERITED (factory) { } 196 virtual ~GrGLSweepGradient() { } 197 198 virtual void emitCode(GrGLProgramBuilder*, 199 const GrFragmentProcessor&, 200 const GrProcessorKey&, 201 const char* outputColor, 202 const char* inputColor, 203 const TransformedCoordsArray&, 204 const TextureSamplerArray&) SK_OVERRIDE; 205 206 static void GenKey(const GrProcessor& processor, const GrGLCaps&, GrProcessorKeyBuilder* b) { 207 b->add32(GenBaseGradientKey(processor)); 208 } 209 210 private: 211 212 typedef GrGLGradientEffect INHERITED; 213 214 }; 215 216 ///////////////////////////////////////////////////////////////////// 217 218 class GrSweepGradient : public GrGradientEffect { 219 public: 220 static GrFragmentProcessor* Create(GrContext* ctx, const SkSweepGradient& shader, 221 const SkMatrix& m) { 222 return SkNEW_ARGS(GrSweepGradient, (ctx, shader, m)); 223 } 224 virtual ~GrSweepGradient() { } 225 226 static const char* Name() { return "Sweep Gradient"; } 227 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE { 228 return GrTBackendFragmentProcessorFactory<GrSweepGradient>::getInstance(); 229 } 230 231 typedef GrGLSweepGradient GLProcessor; 232 233 private: 234 GrSweepGradient(GrContext* ctx, 235 const SkSweepGradient& shader, 236 const SkMatrix& matrix) 237 : INHERITED(ctx, shader, matrix, SkShader::kClamp_TileMode) { } 238 GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 239 240 typedef GrGradientEffect INHERITED; 241 }; 242 243 ///////////////////////////////////////////////////////////////////// 244 245 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSweepGradient); 246 247 GrFragmentProcessor* GrSweepGradient::TestCreate(SkRandom* random, 248 GrContext* context, 249 const GrDrawTargetCaps&, 250 GrTexture**) { 251 SkPoint center = {random->nextUScalar1(), random->nextUScalar1()}; 252 253 SkColor colors[kMaxRandomGradientColors]; 254 SkScalar stopsArray[kMaxRandomGradientColors]; 255 SkScalar* stops = stopsArray; 256 SkShader::TileMode tmIgnored; 257 int colorCount = RandomGradientParams(random, colors, &stops, &tmIgnored); 258 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateSweep(center.fX, center.fY, 259 colors, stops, colorCount)); 260 SkPaint paint; 261 GrFragmentProcessor* fp; 262 GrColor paintColor; 263 SkAssertResult(shader->asFragmentProcessor(context, paint, NULL, &paintColor, &fp)); 264 return fp; 265 } 266 267 ///////////////////////////////////////////////////////////////////// 268 269 void GrGLSweepGradient::emitCode(GrGLProgramBuilder* builder, 270 const GrFragmentProcessor&, 271 const GrProcessorKey& key, 272 const char* outputColor, 273 const char* inputColor, 274 const TransformedCoordsArray& coords, 275 const TextureSamplerArray& samplers) { 276 uint32_t baseKey = key.get32(0); 277 this->emitUniforms(builder, baseKey); 278 SkString coords2D = builder->getFragmentShaderBuilder()->ensureFSCoords2D(coords, 0); 279 const GrGLContextInfo ctxInfo = builder->ctxInfo(); 280 SkString t; 281 // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi] 282 // On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int 283 // thus must us -1.0 * %s.x to work correctly 284 if (kIntel_GrGLVendor != ctxInfo.vendor()){ 285 t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", 286 coords2D.c_str(), coords2D.c_str()); 287 } else { 288 t.printf("atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5", 289 coords2D.c_str(), coords2D.c_str()); 290 } 291 this->emitColor(builder, t.c_str(), baseKey, outputColor, inputColor, samplers); 292 } 293 294 ///////////////////////////////////////////////////////////////////// 295 296 bool SkSweepGradient::asFragmentProcessor(GrContext* context, const SkPaint& paint, 297 const SkMatrix* localMatrix, GrColor* paintColor, 298 GrFragmentProcessor** effect) const { 299 300 SkMatrix matrix; 301 if (!this->getLocalMatrix().invert(&matrix)) { 302 return false; 303 } 304 if (localMatrix) { 305 SkMatrix inv; 306 if (!localMatrix->invert(&inv)) { 307 return false; 308 } 309 matrix.postConcat(inv); 310 } 311 matrix.postConcat(fPtsToUnit); 312 313 *effect = GrSweepGradient::Create(context, *this, matrix); 314 *paintColor = SkColor2GrColorJustAlpha(paint.getColor()); 315 316 return true; 317 } 318 319 #else 320 321 bool SkSweepGradient::asFragmentProcessor(GrContext*, const SkPaint&, const SkMatrix*, GrColor*, 322 GrFragmentProcessor**) const { 323 SkDEBUGFAIL("Should not call in GPU-less build"); 324 return false; 325 } 326 327 #endif 328 329 #ifndef SK_IGNORE_TO_STRING 330 void SkSweepGradient::toString(SkString* str) const { 331 str->append("SkSweepGradient: ("); 332 333 str->append("center: ("); 334 str->appendScalar(fCenter.fX); 335 str->append(", "); 336 str->appendScalar(fCenter.fY); 337 str->append(") "); 338 339 this->INHERITED::toString(str); 340 341 str->append(")"); 342 } 343 #endif 344