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