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 #include "SkColorSpaceXformer.h" 9 #include "SkSweepGradient.h" 10 11 #include "SkPM4fPriv.h" 12 #include "SkRasterPipeline.h" 13 14 static SkMatrix translate(SkScalar dx, SkScalar dy) { 15 SkMatrix matrix; 16 matrix.setTranslate(dx, dy); 17 return matrix; 18 } 19 20 SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor& desc) 21 : SkGradientShaderBase(desc, translate(-cx, -cy)) 22 , fCenter(SkPoint::Make(cx, cy)) 23 { 24 // overwrite the tilemode to a canonical value (since sweep ignores it) 25 fTileMode = SkShader::kClamp_TileMode; 26 } 27 28 SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const { 29 if (info) { 30 commonAsAGradient(info); 31 info->fPoint[0] = fCenter; 32 } 33 return kSweep_GradientType; 34 } 35 36 sk_sp<SkFlattenable> SkSweepGradient::CreateProc(SkReadBuffer& buffer) { 37 DescriptorScope desc; 38 if (!desc.unflatten(buffer)) { 39 return nullptr; 40 } 41 const SkPoint center = buffer.readPoint(); 42 return SkGradientShader::MakeSweep(center.x(), center.y(), desc.fColors, 43 std::move(desc.fColorSpace), desc.fPos, desc.fCount, 44 desc.fGradFlags, desc.fLocalMatrix); 45 } 46 47 void SkSweepGradient::flatten(SkWriteBuffer& buffer) const { 48 this->INHERITED::flatten(buffer); 49 buffer.writePoint(fCenter); 50 } 51 52 ///////////////////////////////////////////////////////////////////// 53 54 #if SK_SUPPORT_GPU 55 56 #include "SkGr.h" 57 #include "GrShaderCaps.h" 58 #include "gl/GrGLContext.h" 59 #include "glsl/GrGLSLFragmentShaderBuilder.h" 60 61 class GrSweepGradient : public GrGradientEffect { 62 public: 63 class GLSLSweepProcessor; 64 65 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) { 66 auto processor = sk_sp<GrSweepGradient>(new GrSweepGradient(args)); 67 return processor->isValid() ? std::move(processor) : nullptr; 68 } 69 70 ~GrSweepGradient() override {} 71 72 const char* name() const override { return "Sweep Gradient"; } 73 74 private: 75 GrSweepGradient(const CreateArgs& args) : INHERITED(args, args.fShader->colorsAreOpaque()) { 76 this->initClassID<GrSweepGradient>(); 77 } 78 79 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 80 81 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps, 82 GrProcessorKeyBuilder* b) const override; 83 84 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 85 86 typedef GrGradientEffect INHERITED; 87 }; 88 89 ///////////////////////////////////////////////////////////////////// 90 91 class GrSweepGradient::GLSLSweepProcessor : public GrGradientEffect::GLSLProcessor { 92 public: 93 GLSLSweepProcessor(const GrProcessor&) {} 94 ~GLSLSweepProcessor() override {} 95 96 virtual void emitCode(EmitArgs&) override; 97 98 static void GenKey(const GrProcessor& processor, const GrShaderCaps&, GrProcessorKeyBuilder* b) { 99 b->add32(GenBaseGradientKey(processor)); 100 } 101 102 private: 103 typedef GrGradientEffect::GLSLProcessor INHERITED; 104 105 }; 106 107 ///////////////////////////////////////////////////////////////////// 108 109 GrGLSLFragmentProcessor* GrSweepGradient::onCreateGLSLInstance() const { 110 return new GrSweepGradient::GLSLSweepProcessor(*this); 111 } 112 113 void GrSweepGradient::onGetGLSLProcessorKey(const GrShaderCaps& caps, 114 GrProcessorKeyBuilder* b) const { 115 GrSweepGradient::GLSLSweepProcessor::GenKey(*this, caps, b); 116 } 117 118 119 ///////////////////////////////////////////////////////////////////// 120 121 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSweepGradient); 122 123 #if GR_TEST_UTILS 124 sk_sp<GrFragmentProcessor> GrSweepGradient::TestCreate(GrProcessorTestData* d) { 125 SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()}; 126 127 RandomGradientParams params(d->fRandom); 128 auto shader = params.fUseColors4f ? 129 SkGradientShader::MakeSweep(center.fX, center.fY, params.fColors4f, params.fColorSpace, 130 params.fStops, params.fColorCount) : 131 SkGradientShader::MakeSweep(center.fX, center.fY, params.fColors, 132 params.fStops, params.fColorCount); 133 GrTest::TestAsFPArgs asFPArgs(d); 134 sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args()); 135 GrAlwaysAssert(fp); 136 return fp; 137 } 138 #endif 139 140 ///////////////////////////////////////////////////////////////////// 141 142 void GrSweepGradient::GLSLSweepProcessor::emitCode(EmitArgs& args) { 143 const GrSweepGradient& ge = args.fFp.cast<GrSweepGradient>(); 144 this->emitUniforms(args.fUniformHandler, ge); 145 SkString coords2D = args.fFragBuilder->ensureCoords2D(args.fTransformedCoords[0]); 146 SkString t; 147 // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi] 148 if (args.fShaderCaps->atan2ImplementedAsAtanYOverX()) { 149 // On some devices they incorrectly implement atan2(y,x) as atan(y/x). In actuality it is 150 // atan2(y,x) = 2 * atan(y / (sqrt(x^2 + y^2) + x)). So to work around this we pass in 151 // (sqrt(x^2 + y^2) + x) as the second parameter to atan2 in these cases. We let the device 152 // handle the undefined behavior of the second paramenter being 0 instead of doing the 153 // divide ourselves and using atan instead. 154 t.printf("(2.0 * atan(- %s.y, length(%s) - %s.x) * 0.1591549430918 + 0.5)", 155 coords2D.c_str(), coords2D.c_str(), coords2D.c_str()); 156 } else { 157 t.printf("(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5)", 158 coords2D.c_str(), coords2D.c_str()); 159 } 160 this->emitColor(args.fFragBuilder, 161 args.fUniformHandler, 162 args.fShaderCaps, 163 ge, t.c_str(), 164 args.fOutputColor, 165 args.fInputColor, 166 args.fTexSamplers); 167 } 168 169 ///////////////////////////////////////////////////////////////////// 170 171 sk_sp<GrFragmentProcessor> SkSweepGradient::asFragmentProcessor(const AsFPArgs& args) const { 172 173 SkMatrix matrix; 174 if (!this->getLocalMatrix().invert(&matrix)) { 175 return nullptr; 176 } 177 if (args.fLocalMatrix) { 178 SkMatrix inv; 179 if (!args.fLocalMatrix->invert(&inv)) { 180 return nullptr; 181 } 182 matrix.postConcat(inv); 183 } 184 matrix.postConcat(fPtsToUnit); 185 186 sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(), 187 args.fDstColorSpace); 188 sk_sp<GrFragmentProcessor> inner(GrSweepGradient::Make( 189 GrGradientEffect::CreateArgs(args.fContext, this, &matrix, SkShader::kClamp_TileMode, 190 std::move(colorSpaceXform), SkToBool(args.fDstColorSpace)))); 191 if (!inner) { 192 return nullptr; 193 } 194 return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner)); 195 } 196 197 #endif 198 199 sk_sp<SkShader> SkSweepGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 200 SkSTArray<8, SkColor> xformedColors(fColorCount); 201 xformer->apply(xformedColors.begin(), fOrigColors, fColorCount); 202 return SkGradientShader::MakeSweep(fCenter.fX, fCenter.fY, xformedColors.begin(), fOrigPos, 203 fColorCount, fGradFlags, &this->getLocalMatrix()); 204 } 205 206 #ifndef SK_IGNORE_TO_STRING 207 void SkSweepGradient::toString(SkString* str) const { 208 str->append("SkSweepGradient: ("); 209 210 str->append("center: ("); 211 str->appendScalar(fCenter.fX); 212 str->append(", "); 213 str->appendScalar(fCenter.fY); 214 str->append(") "); 215 216 this->INHERITED::toString(str); 217 218 str->append(")"); 219 } 220 221 bool SkSweepGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc, 222 SkMatrix* matrix, 223 SkRasterPipeline* p, 224 SkRasterPipeline*) const { 225 matrix->postTranslate(-fCenter.fX, -fCenter.fY); 226 p->append(SkRasterPipeline::xy_to_unit_angle); 227 228 return true; 229 } 230 231 #endif 232