1561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes/* 2561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes * Copyright 2014 Google Inc. 3561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes * 4561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes * Use of this source code is governed by a BSD-style license that can be 5561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes * found in the LICENSE file. 6561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes */ 7561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 8561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "gl/builders/GrGLProgramBuilder.h" 9561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "GrRRectEffect.h" 10561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 11561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "gl/GrGLProcessor.h" 12561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "gl/GrGLSL.h" 13561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "GrConvexPolyEffect.h" 14561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "GrOvalEffect.h" 15561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "GrTBackendProcessorFactory.h" 16561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 17561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "SkRRect.h" 18561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 198d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath// The effects defined here only handle rrect radii >= kRadiusMin. 208d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathstatic const SkScalar kRadiusMin = SK_ScalarHalf; 21561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 22561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes////////////////////////////////////////////////////////////////////////////// 23561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 24561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesclass GLCircularRRectEffect; 25561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 26561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesclass CircularRRectEffect : public GrFragmentProcessor { 27561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughespublic: 28561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 29561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes enum CornerFlags { 30561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes kTopLeft_CornerFlag = (1 << SkRRect::kUpperLeft_Corner), 31561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes kTopRight_CornerFlag = (1 << SkRRect::kUpperRight_Corner), 32561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner), 33561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes kBottomLeft_CornerFlag = (1 << SkRRect::kLowerLeft_Corner), 34561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 35561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes kLeft_CornerFlags = kTopLeft_CornerFlag | kBottomLeft_CornerFlag, 36561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes kTop_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag, 37561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes kRight_CornerFlags = kTopRight_CornerFlag | kBottomRight_CornerFlag, 388d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag, 39561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 40561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes kAll_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag | 41561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes kBottomLeft_CornerFlag | kBottomRight_CornerFlag, 42561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 43561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes kNone_CornerFlags = 0 44561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes }; 45561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 46561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes // The flags are used to indicate which corners are circluar (unflagged corners are assumed to 47561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes // be square). 48561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes static GrFragmentProcessor* Create(GrPrimitiveEdgeType, uint32_t circularCornerFlags, 49561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const SkRRect&); 50561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 51561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes virtual ~CircularRRectEffect() {}; 52561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes static const char* Name() { return "CircularRRect"; } 53561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 548d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const SkRRect& getRRect() const { return fRRect; } 55561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 56561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes uint32_t getCircularCornerFlags() const { return fCircularCornerFlags; } 57561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 58561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } 59561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 60561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes typedef GLCircularRRectEffect GLProcessor; 61561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 62561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; 63561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 64561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE; 65561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 66561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesprivate: 67561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes CircularRRectEffect(GrPrimitiveEdgeType, uint32_t circularCornerFlags, const SkRRect&); 68561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 69561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE; 708d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 718d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath SkRRect fRRect; 72561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrPrimitiveEdgeType fEdgeType; 73561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes uint32_t fCircularCornerFlags; 74561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 75561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 76561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 778d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath typedef GrFragmentProcessor INHERITED; 78561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}; 79561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 808d8858e39800de641b50f6e8e864af9cf68bedeaNarayan KamathGrFragmentProcessor* CircularRRectEffect::Create(GrPrimitiveEdgeType edgeType, 81561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes uint32_t circularCornerFlags, 82561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const SkRRect& rrect) { 83561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes if (kFillAA_GrProcessorEdgeType != edgeType && kInverseFillAA_GrProcessorEdgeType != edgeType) { 84561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes return NULL; 85561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes } 86561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes return SkNEW_ARGS(CircularRRectEffect, (edgeType, circularCornerFlags, rrect)); 87561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes} 88561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 89561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesvoid CircularRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { 90561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes *validFlags = 0; 91561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes} 92561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 93561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesconst GrBackendFragmentProcessorFactory& CircularRRectEffect::getFactory() const { 94561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes return GrTBackendFragmentProcessorFactory<CircularRRectEffect>::getInstance(); 95561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes} 96561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 97561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesCircularRRectEffect::CircularRRectEffect(GrPrimitiveEdgeType edgeType, uint32_t circularCornerFlags, 98561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const SkRRect& rrect) 998d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath : fRRect(rrect) 100561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes , fEdgeType(edgeType) 101561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes , fCircularCornerFlags(circularCornerFlags) { 102561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes this->setWillReadFragmentPosition(); 103561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes} 104561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 105561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesbool CircularRRectEffect::onIsEqual(const GrProcessor& other) const { 106561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const CircularRRectEffect& crre = other.cast<CircularRRectEffect>(); 107561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes // The corner flags are derived from fRRect, so no need to check them. 108561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect; 109561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes} 110561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 111561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes////////////////////////////////////////////////////////////////////////////// 112561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 113561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesGR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircularRRectEffect); 114561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 1158d8858e39800de641b50f6e8e864af9cf68bedeaNarayan KamathGrFragmentProcessor* CircularRRectEffect::TestCreate(SkRandom* random, 1168d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath GrContext*, 1178d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const GrDrawTargetCaps& caps, 1188d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath GrTexture*[]) { 1198d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath SkScalar w = random->nextRangeScalar(20.f, 1000.f); 1208d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath SkScalar h = random->nextRangeScalar(20.f, 1000.f); 1218d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath SkScalar r = random->nextRangeF(kRadiusMin, 9.f); 1228d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath SkRRect rrect; 1238d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rrect.setRectXY(SkRect::MakeWH(w, h), r, r); 1248d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath GrFragmentProcessor* fp; 125561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes do { 126561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrPrimitiveEdgeType et = 127561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes (GrPrimitiveEdgeType)random->nextULessThan(kGrProcessorEdgeTypeCnt); 1288d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fp = GrRRectEffect::Create(et, rrect); 129561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes } while (NULL == fp); 130561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes return fp; 1318d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath} 132561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 133561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes////////////////////////////////////////////////////////////////////////////// 134561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 1358d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathclass GLCircularRRectEffect : public GrGLFragmentProcessor { 136561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughespublic: 137561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GLCircularRRectEffect(const GrBackendProcessorFactory&, const GrProcessor&); 138561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 139561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes virtual void emitCode(GrGLProgramBuilder* builder, 1408d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const GrFragmentProcessor& fp, 141561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const GrProcessorKey& key, 142561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const char* outputColor, 143561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const char* inputColor, 144561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const TransformedCoordsArray&, 145561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const TextureSamplerArray&) SK_OVERRIDE; 1468d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 147561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*); 148561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 149561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE; 150561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 151561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesprivate: 152561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrGLProgramDataManager::UniformHandle fInnerRectUniform; 153561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrGLProgramDataManager::UniformHandle fRadiusPlusHalfUniform; 154561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes SkRRect fPrevRRect; 155561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes typedef GrGLFragmentProcessor INHERITED; 156561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}; 157561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 158561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesGLCircularRRectEffect::GLCircularRRectEffect(const GrBackendProcessorFactory& factory, 159561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const GrProcessor& ) 160561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes : INHERITED (factory) { 161561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fPrevRRect.setEmpty(); 162561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes} 1638d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 1648d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathvoid GLCircularRRectEffect::emitCode(GrGLProgramBuilder* builder, 1658d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const GrFragmentProcessor& fp, 1668d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const GrProcessorKey& key, 1678d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const char* outputColor, 1688d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const char* inputColor, 1698d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const TransformedCoordsArray&, 1708d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const TextureSamplerArray& samplers) { 1718d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const CircularRRectEffect& crre = fp.cast<CircularRRectEffect>(); 1728d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const char *rectName; 1738d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const char *radiusPlusHalfName; 1748d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom 1758d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has 1768d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // only rectangular corners, that side's value corresponds to the rect edge's value outset by 1778d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // half a pixel. 1788d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fInnerRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, 1798d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath kVec4f_GrSLType, 1808d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath "innerRect", 1818d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath &rectName); 1828d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fRadiusPlusHalfUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, 1838d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath kFloat_GrSLType, 1848d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath "radiusPlusHalf", 1858d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath &radiusPlusHalfName); 1868d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 1878d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder(); 1888d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const char* fragmentPos = fsBuilder->fragmentPosition(); 1898d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // At each quarter-circle corner we compute a vector that is the offset of the fragment position 1908d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant 1918d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // to that corner. This means that points near the interior near the rrect top edge will have 1928d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // a vector that points straight up for both the TL left and TR corners. Computing an 1938d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // alpha from this vector at either the TR or TL corner will give the correct result. Similarly, 1948d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // fragments near the other three edges will get the correct AA. Fragments in the interior of 1958d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will 1968d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas. 1978d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // The code below is a simplified version of the above that performs maxs on the vector 1988d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // components before computing distances and alpha values so that only one distance computation 1998d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // need be computed to determine the min alpha. 2008d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // 2018d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // For the cases where one half of the rrect is rectangular we drop one of the x or y 2028d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // computations, compute a separate rect edge alpha for the rect side, and mul the two computed 2038d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // alphas together. 2048d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath switch (crre.getCircularCornerFlags()) { 2058d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath case CircularRRectEffect::kAll_CornerFlags: 2068d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos); 2078d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName); 2088d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); 2098d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n", 2108d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath radiusPlusHalfName); 2118d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath break; 2128d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath case CircularRRectEffect::kTopLeft_CornerFlag: 2138d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n", 2148d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rectName, fragmentPos); 2158d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n", 2168d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rectName, fragmentPos); 2178d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n", 2188d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rectName, fragmentPos); 2198d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 2208d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath radiusPlusHalfName); 2218d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath break; 2228d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath case CircularRRectEffect::kTopRight_CornerFlag: 2238d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n", 2248d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fragmentPos, rectName, rectName, fragmentPos); 2258d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n", 2268d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fragmentPos, rectName); 2278d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n", 2288d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rectName, fragmentPos); 2298d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 2308d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath radiusPlusHalfName); 2318d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath break; 2328d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath case CircularRRectEffect::kBottomRight_CornerFlag: 2338d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n", 2348d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fragmentPos, rectName); 2358d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n", 2368d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fragmentPos, rectName); 2378d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", 2388d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fragmentPos, rectName); 2398d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 2408d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath radiusPlusHalfName); 2418d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath break; 2428d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath case CircularRRectEffect::kBottomLeft_CornerFlag: 243561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n", 244561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rectName, fragmentPos, fragmentPos, rectName); 245561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n", 2468d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rectName, fragmentPos); 247561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", 248561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fragmentPos, rectName); 2498d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 250561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes radiusPlusHalfName); 251561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes break; 2528d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath case CircularRRectEffect::kLeft_CornerFlags: 253561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos); 2548d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName); 255561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n"); 2568d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n", 257561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rectName, fragmentPos); 258561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 259561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes radiusPlusHalfName); 2608d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath break; 261561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes case CircularRRectEffect::kTop_CornerFlags: 262561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos); 263561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName); 264561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n"); 2658d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n", 266561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rectName, fragmentPos); 267561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 268561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes radiusPlusHalfName); 269561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes break; 270561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes case CircularRRectEffect::kRight_CornerFlags: 2718d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos); 272561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName); 273561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n"); 274561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n", 275561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fragmentPos, rectName); 276561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 277561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes radiusPlusHalfName); 278561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes break; 279561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes case CircularRRectEffect::kBottom_CornerFlags: 280561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos); 281561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName); 282561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n"); 283561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", 284561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fragmentPos, rectName); 2858d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", 286561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes radiusPlusHalfName); 2878d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath break; 288561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes } 289561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 290561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes if (kInverseFillAA_GrProcessorEdgeType == crre.getEdgeType()) { 291561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fsBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n"); 292561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes } 2938d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 2948d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor, 2958d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str()); 2968d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath} 2978d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 2988d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathvoid GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrGLCaps&, 2998d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath GrProcessorKeyBuilder* b) { 300561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>(); 301561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8); 302561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes b->add32((crre.getCircularCornerFlags() << 3) | crre.getEdgeType()); 303561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes} 3048d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 305561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesvoid GLCircularRRectEffect::setData(const GrGLProgramDataManager& pdman, 3068d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const GrProcessor& processor) { 307561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>(); 308561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const SkRRect& rrect = crre.getRRect(); 3098d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath if (rrect != fPrevRRect) { 310561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes SkRect rect = rrect.getBounds(); 311561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes SkScalar radius = 0; 3128d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath switch (crre.getCircularCornerFlags()) { 3138d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath case CircularRRectEffect::kAll_CornerFlags: 3148d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath SkASSERT(rrect.isSimpleCircular()); 3158d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath radius = rrect.getSimpleRadii().fX; 3168d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath SkASSERT(radius >= kRadiusMin); 3178d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rect.inset(radius, radius); 3188d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath break; 319561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes case CircularRRectEffect::kTopLeft_CornerFlag: 320561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 321561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fLeft += radius; 322561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fTop += radius; 3238d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rect.fRight += 0.5f; 324561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fBottom += 0.5f; 3258d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath break; 326561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes case CircularRRectEffect::kTopRight_CornerFlag: 327561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes radius = rrect.radii(SkRRect::kUpperRight_Corner).fX; 328561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fLeft -= 0.5f; 3298d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rect.fTop += radius; 330561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fRight -= radius; 331561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fBottom += 0.5f; 332561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes break; 333561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes case CircularRRectEffect::kBottomRight_CornerFlag: 3348d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath radius = rrect.radii(SkRRect::kLowerRight_Corner).fX; 335561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fLeft -= 0.5f; 3368d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rect.fTop -= 0.5f; 337561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fRight -= radius; 338561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fBottom -= radius; 3398d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath break; 3408d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath case CircularRRectEffect::kBottomLeft_CornerFlag: 341561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX; 342561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fLeft += radius; 343561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fTop -= 0.5f; 344561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fRight += 0.5f; 3458d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rect.fBottom -= radius; 346561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes break; 3478d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath case CircularRRectEffect::kLeft_CornerFlags: 348561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 349561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fLeft += radius; 3508d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rect.fTop += radius; 3518d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rect.fRight += 0.5f; 3528d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rect.fBottom -= radius; 3538d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath break; 354561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes case CircularRRectEffect::kTop_CornerFlags: 355561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 356561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fLeft += radius; 357561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fTop += radius; 3588d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rect.fRight -= radius; 3598d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rect.fBottom += 0.5f; 360561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes break; 361561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes case CircularRRectEffect::kRight_CornerFlags: 3628d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath radius = rrect.radii(SkRRect::kUpperRight_Corner).fX; 363561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fLeft -= 0.5f; 364561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fTop += radius; 365561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fRight -= radius; 366561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fBottom -= radius; 367561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes break; 3688d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath case CircularRRectEffect::kBottom_CornerFlags: 3698d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX; 370561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fLeft += radius; 371561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fTop -= 0.5f; 372561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fRight -= radius; 373561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rect.fBottom -= radius; 374561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes break; 375561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes default: 376561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes SkFAIL("Should have been one of the above cases."); 3778d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath } 378561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); 3798d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath pdman.set1f(fRadiusPlusHalfUniform, radius + 0.5f); 380561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fPrevRRect = rrect; 381561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes } 3828d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath} 3838d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 3848d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath////////////////////////////////////////////////////////////////////////////// 385561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 386561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesclass GLEllipticalRRectEffect; 387561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 388561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesclass EllipticalRRectEffect : public GrFragmentProcessor { 3898d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathpublic: 390561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes static GrFragmentProcessor* Create(GrPrimitiveEdgeType, const SkRRect&); 3918d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 392561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes virtual ~EllipticalRRectEffect() {}; 393561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes static const char* Name() { return "EllipticalRRect"; } 3948d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 395561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const SkRRect& getRRect() const { return fRRect; } 396561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 3978d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 398561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } 399561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 400561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes typedef GLEllipticalRRectEffect GLProcessor; 401561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 402561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; 4038d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 4048d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE; 405561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 406561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesprivate: 407561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes EllipticalRRectEffect(GrPrimitiveEdgeType, const SkRRect&); 408561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 409561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE; 4108d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 411561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes SkRRect fRRect; 412561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrPrimitiveEdgeType fEdgeType; 413561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 414561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 415561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 4168d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath typedef GrFragmentProcessor INHERITED; 417561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}; 418561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 419561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesGrFragmentProcessor* 420561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesEllipticalRRectEffect::Create(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) { 421561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes if (kFillAA_GrProcessorEdgeType != edgeType && kInverseFillAA_GrProcessorEdgeType != edgeType) { 422561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes return NULL; 423561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes } 424561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes return SkNEW_ARGS(EllipticalRRectEffect, (edgeType, rrect)); 4258d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath} 426561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 427561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesvoid EllipticalRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { 428561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes *validFlags = 0; 429561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes} 430561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 431561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesconst GrBackendFragmentProcessorFactory& EllipticalRRectEffect::getFactory() const { 432561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes return GrTBackendFragmentProcessorFactory<EllipticalRRectEffect>::getInstance(); 433561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes} 4348d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 435561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesEllipticalRRectEffect::EllipticalRRectEffect(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) 436561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes : fRRect(rrect) 437561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes , fEdgeType(edgeType){ 438561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes this->setWillReadFragmentPosition(); 439561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes} 440561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 441561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesbool EllipticalRRectEffect::onIsEqual(const GrProcessor& other) const { 442561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const EllipticalRRectEffect& erre = other.cast<EllipticalRRectEffect>(); 4438d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect; 444561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes} 445561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 446561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes////////////////////////////////////////////////////////////////////////////// 447561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 448561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesGR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipticalRRectEffect); 449561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 450561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesGrFragmentProcessor* EllipticalRRectEffect::TestCreate(SkRandom* random, 451561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrContext*, 4528d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const GrDrawTargetCaps& caps, 453561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrTexture*[]) { 454561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes SkScalar w = random->nextRangeScalar(20.f, 1000.f); 455561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes SkScalar h = random->nextRangeScalar(20.f, 1000.f); 4568d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath SkVector r[4]; 457561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes r[SkRRect::kUpperLeft_Corner].fX = random->nextRangeF(kRadiusMin, 9.f); 458561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes // ensure at least one corner really is elliptical 4598d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath do { 460561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes r[SkRRect::kUpperLeft_Corner].fY = random->nextRangeF(kRadiusMin, 9.f); 461561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX); 462561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 463561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes SkRRect rrect; 464561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes if (random->nextBool()) { 465561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes // half the time create a four-radii rrect. 4668d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath r[SkRRect::kLowerRight_Corner].fX = random->nextRangeF(kRadiusMin, 9.f); 467561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes r[SkRRect::kLowerRight_Corner].fY = random->nextRangeF(kRadiusMin, 9.f); 468561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 469561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX; 470561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY; 471561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 472561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX; 473561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY; 474561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 4758d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath rrect.setRectRadii(SkRect::MakeWH(w, h), r); 476561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes } else { 477561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX, 478561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes r[SkRRect::kUpperLeft_Corner].fY); 4798d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath } 480561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrFragmentProcessor* fp; 481561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes do { 482561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)random->nextULessThan(kGrProcessorEdgeTypeCnt); 483561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fp = GrRRectEffect::Create(et, rrect); 484561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes } while (NULL == fp); 485561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes return fp; 4868d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath} 487561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 488561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes////////////////////////////////////////////////////////////////////////////// 489561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 490561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesclass GLEllipticalRRectEffect : public GrGLFragmentProcessor { 4918d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathpublic: 492561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GLEllipticalRRectEffect(const GrBackendProcessorFactory&, const GrProcessor&); 493561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 494561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes virtual void emitCode(GrGLProgramBuilder* builder, 495561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const GrFragmentProcessor& effect, 496561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const GrProcessorKey& key, 4978d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath const char* outputColor, 498561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const char* inputColor, 499561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const TransformedCoordsArray&, 500561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const TextureSamplerArray&) SK_OVERRIDE; 501561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 502561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*); 503561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 504561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE; 505561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 506561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesprivate: 507561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrGLProgramDataManager::UniformHandle fInnerRectUniform; 508561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrGLProgramDataManager::UniformHandle fInvRadiiSqdUniform; 509561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes SkRRect fPrevRRect; 5108d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath typedef GrGLFragmentProcessor INHERITED; 511561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes}; 512561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 513561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott HughesGLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrBackendProcessorFactory& factory, 514561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const GrProcessor& effect) 515561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes : INHERITED (factory) { 516561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fPrevRRect.setEmpty(); 517561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes} 5188d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath 519561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesvoid GLEllipticalRRectEffect::emitCode(GrGLProgramBuilder* builder, 520561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const GrFragmentProcessor& effect, 521561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const GrProcessorKey& key, 522561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const char* outputColor, 523561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const char* inputColor, 524561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const TransformedCoordsArray&, 525561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const TextureSamplerArray& samplers) { 526561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); 527561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const char *rectName; 5288d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // The inner rect is the rrect bounds inset by the x/y radii 529561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes fInnerRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, 530561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes kVec4f_GrSLType, 531561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes "innerRect", 532561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes &rectName); 533561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes 534561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder(); 535561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes const char* fragmentPos = fsBuilder->fragmentPosition(); 5368d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos 537561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant 538561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes // to that corner. This means that points near the interior near the rrect top edge will have 539561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes // a vector that points straight up for both the TL left and TR corners. Computing an 540 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly, 541 // fragments near the other three edges will get the correct AA. Fragments in the interior of 542 // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will 543 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas. 544 // The code below is a simplified version of the above that performs maxs on the vector 545 // components before computing distances and alpha values so that only one distance computation 546 // need be computed to determine the min alpha. 547 fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos); 548 fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName); 549 switch (erre.getRRect().getType()) { 550 case SkRRect::kSimple_Type: { 551 const char *invRadiiXYSqdName; 552 fInvRadiiSqdUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, 553 kVec2f_GrSLType, 554 "invRadiiXY", 555 &invRadiiXYSqdName); 556 fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); 557 // Z is the x/y offsets divided by squared radii. 558 fsBuilder->codeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName); 559 break; 560 } 561 case SkRRect::kNinePatch_Type: { 562 const char *invRadiiLTRBSqdName; 563 fInvRadiiSqdUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, 564 kVec4f_GrSLType, 565 "invRadiiLTRB", 566 &invRadiiLTRBSqdName); 567 fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); 568 // Z is the x/y offsets divided by squared radii. We only care about the (at most) one 569 // corner where both the x and y offsets are positive, hence the maxes. (The inverse 570 // squared radii will always be positive.) 571 fsBuilder->codeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n", 572 invRadiiLTRBSqdName, invRadiiLTRBSqdName); 573 break; 574 } 575 default: 576 SkFAIL("RRect should always be simple or nine-patch."); 577 } 578 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1. 579 fsBuilder->codeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n"); 580 // grad_dot is the squared length of the gradient of the implicit. 581 fsBuilder->codeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n"); 582 // avoid calling inversesqrt on zero. 583 fsBuilder->codeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n"); 584 fsBuilder->codeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n"); 585 586 if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) { 587 fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n"); 588 } else { 589 fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n"); 590 } 591 592 fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor, 593 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str()); 594} 595 596void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrGLCaps&, 597 GrProcessorKeyBuilder* b) { 598 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); 599 GR_STATIC_ASSERT(kLast_GrProcessorEdgeType < (1 << 3)); 600 b->add32(erre.getRRect().getType() | erre.getEdgeType() << 3); 601} 602 603void GLEllipticalRRectEffect::setData(const GrGLProgramDataManager& pdman, 604 const GrProcessor& effect) { 605 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); 606 const SkRRect& rrect = erre.getRRect(); 607 if (rrect != fPrevRRect) { 608 SkRect rect = rrect.getBounds(); 609 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); 610 SkASSERT(r0.fX >= kRadiusMin); 611 SkASSERT(r0.fY >= kRadiusMin); 612 switch (erre.getRRect().getType()) { 613 case SkRRect::kSimple_Type: 614 rect.inset(r0.fX, r0.fY); 615 pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 616 1.f / (r0.fY * r0.fY)); 617 break; 618 case SkRRect::kNinePatch_Type: { 619 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); 620 SkASSERT(r1.fX >= kRadiusMin); 621 SkASSERT(r1.fY >= kRadiusMin); 622 rect.fLeft += r0.fX; 623 rect.fTop += r0.fY; 624 rect.fRight -= r1.fX; 625 rect.fBottom -= r1.fY; 626 pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 627 1.f / (r0.fY * r0.fY), 628 1.f / (r1.fX * r1.fX), 629 1.f / (r1.fY * r1.fY)); 630 break; 631 } 632 default: 633 SkFAIL("RRect should always be simple or nine-patch."); 634 } 635 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); 636 fPrevRRect = rrect; 637 } 638} 639 640////////////////////////////////////////////////////////////////////////////// 641 642GrFragmentProcessor* GrRRectEffect::Create(GrPrimitiveEdgeType edgeType, const SkRRect& rrect) { 643 if (rrect.isRect()) { 644 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds()); 645 } 646 647 if (rrect.isOval()) { 648 return GrOvalEffect::Create(edgeType, rrect.getBounds()); 649 } 650 651 if (rrect.isSimple()) { 652 if (rrect.getSimpleRadii().fX < kRadiusMin || rrect.getSimpleRadii().fY < kRadiusMin) { 653 // In this case the corners are extremely close to rectangular and we collapse the 654 // clip to a rectangular clip. 655 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds()); 656 } 657 if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) { 658 return CircularRRectEffect::Create(edgeType, CircularRRectEffect::kAll_CornerFlags, 659 rrect); 660 } else { 661 return EllipticalRRectEffect::Create(edgeType, rrect); 662 } 663 } 664 665 if (rrect.isComplex() || rrect.isNinePatch()) { 666 // Check for the "tab" cases - two adjacent circular corners and two square corners. 667 SkScalar circularRadius = 0; 668 uint32_t cornerFlags = 0; 669 670 SkVector radii[4]; 671 bool squashedRadii = false; 672 for (int c = 0; c < 4; ++c) { 673 radii[c] = rrect.radii((SkRRect::Corner)c); 674 SkASSERT((0 == radii[c].fX) == (0 == radii[c].fY)); 675 if (0 == radii[c].fX) { 676 // The corner is square, so no need to squash or flag as circular. 677 continue; 678 } 679 if (radii[c].fX < kRadiusMin || radii[c].fY < kRadiusMin) { 680 radii[c].set(0, 0); 681 squashedRadii = true; 682 continue; 683 } 684 if (radii[c].fX != radii[c].fY) { 685 cornerFlags = ~0U; 686 break; 687 } 688 if (!cornerFlags) { 689 circularRadius = radii[c].fX; 690 cornerFlags = 1 << c; 691 } else { 692 if (radii[c].fX != circularRadius) { 693 cornerFlags = ~0U; 694 break; 695 } 696 cornerFlags |= 1 << c; 697 } 698 } 699 700 switch (cornerFlags) { 701 case CircularRRectEffect::kAll_CornerFlags: 702 // This rrect should have been caught in the simple case above. Though, it would 703 // be correctly handled in the fallthrough code. 704 SkASSERT(false); 705 case CircularRRectEffect::kTopLeft_CornerFlag: 706 case CircularRRectEffect::kTopRight_CornerFlag: 707 case CircularRRectEffect::kBottomRight_CornerFlag: 708 case CircularRRectEffect::kBottomLeft_CornerFlag: 709 case CircularRRectEffect::kLeft_CornerFlags: 710 case CircularRRectEffect::kTop_CornerFlags: 711 case CircularRRectEffect::kRight_CornerFlags: 712 case CircularRRectEffect::kBottom_CornerFlags: { 713 SkTCopyOnFirstWrite<SkRRect> rr(rrect); 714 if (squashedRadii) { 715 rr.writable()->setRectRadii(rrect.getBounds(), radii); 716 } 717 return CircularRRectEffect::Create(edgeType, cornerFlags, *rr); 718 } 719 case CircularRRectEffect::kNone_CornerFlags: 720 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds()); 721 default: { 722 if (squashedRadii) { 723 // If we got here then we squashed some but not all the radii to zero. (If all 724 // had been squashed cornerFlags would be 0.) The elliptical effect doesn't 725 // support some rounded and some square corners. 726 return NULL; 727 } 728 if (rrect.isNinePatch()) { 729 return EllipticalRRectEffect::Create(edgeType, rrect); 730 } 731 return NULL; 732 } 733 } 734 } 735 736 return NULL; 737} 738