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