1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/gpu/effects/GrConvexPolyEffect.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,374 @@ 1.4 +/* 1.5 + * Copyright 2014 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "GrConvexPolyEffect.h" 1.12 + 1.13 +#include "gl/GrGLEffect.h" 1.14 +#include "gl/GrGLSL.h" 1.15 +#include "GrTBackendEffectFactory.h" 1.16 + 1.17 +#include "SkPath.h" 1.18 + 1.19 +////////////////////////////////////////////////////////////////////////////// 1.20 +class GLAARectEffect; 1.21 + 1.22 +class AARectEffect : public GrEffect { 1.23 +public: 1.24 + typedef GLAARectEffect GLEffect; 1.25 + 1.26 + const SkRect& getRect() const { return fRect; } 1.27 + 1.28 + static const char* Name() { return "AARect"; } 1.29 + 1.30 + static GrEffectRef* Create(GrEffectEdgeType edgeType, const SkRect& rect) { 1.31 + return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(AARectEffect, (edgeType, rect)))); 1.32 + } 1.33 + 1.34 + virtual void getConstantColorComponents(GrColor* color, 1.35 + uint32_t* validFlags) const SK_OVERRIDE { 1.36 + if (fRect.isEmpty()) { 1.37 + // An empty rect will have no coverage anywhere. 1.38 + *color = 0x00000000; 1.39 + *validFlags = kRGBA_GrColorComponentFlags; 1.40 + } else { 1.41 + *validFlags = 0; 1.42 + } 1.43 + } 1.44 + 1.45 + GrEffectEdgeType getEdgeType() const { return fEdgeType; } 1.46 + 1.47 + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; 1.48 + 1.49 +private: 1.50 + AARectEffect(GrEffectEdgeType edgeType, const SkRect& rect) : fRect(rect), fEdgeType(edgeType) { 1.51 + this->setWillReadFragmentPosition(); 1.52 + } 1.53 + 1.54 + virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { 1.55 + const AARectEffect& aare = CastEffect<AARectEffect>(other); 1.56 + return fRect == aare.fRect; 1.57 + } 1.58 + 1.59 + SkRect fRect; 1.60 + GrEffectEdgeType fEdgeType; 1.61 + 1.62 + typedef GrEffect INHERITED; 1.63 + 1.64 + GR_DECLARE_EFFECT_TEST; 1.65 + 1.66 +}; 1.67 + 1.68 +GR_DEFINE_EFFECT_TEST(AARectEffect); 1.69 + 1.70 +GrEffectRef* AARectEffect::TestCreate(SkRandom* random, 1.71 + GrContext*, 1.72 + const GrDrawTargetCaps& caps, 1.73 + GrTexture*[]) { 1.74 + SkRect rect = SkRect::MakeLTRB(random->nextSScalar1(), 1.75 + random->nextSScalar1(), 1.76 + random->nextSScalar1(), 1.77 + random->nextSScalar1()); 1.78 + GrEffectRef* effect; 1.79 + do { 1.80 + GrEffectEdgeType edgeType = static_cast<GrEffectEdgeType>(random->nextULessThan( 1.81 + kGrEffectEdgeTypeCnt)); 1.82 + 1.83 + effect = AARectEffect::Create(edgeType, rect); 1.84 + } while (NULL == effect); 1.85 + return effect; 1.86 +} 1.87 + 1.88 +////////////////////////////////////////////////////////////////////////////// 1.89 + 1.90 +class GLAARectEffect : public GrGLEffect { 1.91 +public: 1.92 + GLAARectEffect(const GrBackendEffectFactory&, const GrDrawEffect&); 1.93 + 1.94 + virtual void emitCode(GrGLShaderBuilder* builder, 1.95 + const GrDrawEffect& drawEffect, 1.96 + EffectKey key, 1.97 + const char* outputColor, 1.98 + const char* inputColor, 1.99 + const TransformedCoordsArray&, 1.100 + const TextureSamplerArray&) SK_OVERRIDE; 1.101 + 1.102 + static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); 1.103 + 1.104 + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; 1.105 + 1.106 +private: 1.107 + GrGLUniformManager::UniformHandle fRectUniform; 1.108 + SkRect fPrevRect; 1.109 + typedef GrGLEffect INHERITED; 1.110 +}; 1.111 + 1.112 +GLAARectEffect::GLAARectEffect(const GrBackendEffectFactory& factory, 1.113 + const GrDrawEffect& drawEffect) 1.114 + : INHERITED (factory) { 1.115 + fPrevRect.fLeft = SK_ScalarNaN; 1.116 +} 1.117 + 1.118 +void GLAARectEffect::emitCode(GrGLShaderBuilder* builder, 1.119 + const GrDrawEffect& drawEffect, 1.120 + EffectKey key, 1.121 + const char* outputColor, 1.122 + const char* inputColor, 1.123 + const TransformedCoordsArray&, 1.124 + const TextureSamplerArray& samplers) { 1.125 + const AARectEffect& aare = drawEffect.castEffect<AARectEffect>(); 1.126 + const char *rectName; 1.127 + // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5), 1.128 + // respectively. 1.129 + fRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 1.130 + kVec4f_GrSLType, 1.131 + "rect", 1.132 + &rectName); 1.133 + const char* fragmentPos = builder->fragmentPosition(); 1.134 + if (GrEffectEdgeTypeIsAA(aare.getEdgeType())) { 1.135 + // The amount of coverage removed in x and y by the edges is computed as a pair of negative 1.136 + // numbers, xSub and ySub. 1.137 + builder->fsCodeAppend("\t\tfloat xSub, ySub;\n"); 1.138 + builder->fsCodeAppendf("\t\txSub = min(%s.x - %s.x, 0.0);\n", fragmentPos, rectName); 1.139 + builder->fsCodeAppendf("\t\txSub += min(%s.z - %s.x, 0.0);\n", rectName, fragmentPos); 1.140 + builder->fsCodeAppendf("\t\tySub = min(%s.y - %s.y, 0.0);\n", fragmentPos, rectName); 1.141 + builder->fsCodeAppendf("\t\tySub += min(%s.w - %s.y, 0.0);\n", rectName, fragmentPos); 1.142 + // Now compute coverage in x and y and multiply them to get the fraction of the pixel 1.143 + // covered. 1.144 + builder->fsCodeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n"); 1.145 + } else { 1.146 + builder->fsCodeAppendf("\t\tfloat alpha = 1.0;\n"); 1.147 + builder->fsCodeAppendf("\t\talpha *= (%s.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName); 1.148 + builder->fsCodeAppendf("\t\talpha *= (%s.z - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos); 1.149 + builder->fsCodeAppendf("\t\talpha *= (%s.y - %s.y) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName); 1.150 + builder->fsCodeAppendf("\t\talpha *= (%s.w - %s.y) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos); 1.151 + } 1.152 + 1.153 + if (GrEffectEdgeTypeIsInverseFill(aare.getEdgeType())) { 1.154 + builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n"); 1.155 + } 1.156 + builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor, 1.157 + (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str()); 1.158 +} 1.159 + 1.160 +void GLAARectEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { 1.161 + const AARectEffect& aare = drawEffect.castEffect<AARectEffect>(); 1.162 + const SkRect& rect = aare.getRect(); 1.163 + if (rect != fPrevRect) { 1.164 + uman.set4f(fRectUniform, rect.fLeft + 0.5f, rect.fTop + 0.5f, 1.165 + rect.fRight - 0.5f, rect.fBottom - 0.5f); 1.166 + fPrevRect = rect; 1.167 + } 1.168 +} 1.169 + 1.170 +GrGLEffect::EffectKey GLAARectEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 1.171 + const AARectEffect& aare = drawEffect.castEffect<AARectEffect>(); 1.172 + return aare.getEdgeType(); 1.173 +} 1.174 + 1.175 +const GrBackendEffectFactory& AARectEffect::getFactory() const { 1.176 + return GrTBackendEffectFactory<AARectEffect>::getInstance(); 1.177 +} 1.178 + 1.179 +////////////////////////////////////////////////////////////////////////////// 1.180 + 1.181 +class GrGLConvexPolyEffect : public GrGLEffect { 1.182 +public: 1.183 + GrGLConvexPolyEffect(const GrBackendEffectFactory&, const GrDrawEffect&); 1.184 + 1.185 + virtual void emitCode(GrGLShaderBuilder* builder, 1.186 + const GrDrawEffect& drawEffect, 1.187 + EffectKey key, 1.188 + const char* outputColor, 1.189 + const char* inputColor, 1.190 + const TransformedCoordsArray&, 1.191 + const TextureSamplerArray&) SK_OVERRIDE; 1.192 + 1.193 + static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); 1.194 + 1.195 + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; 1.196 + 1.197 +private: 1.198 + GrGLUniformManager::UniformHandle fEdgeUniform; 1.199 + SkScalar fPrevEdges[3 * GrConvexPolyEffect::kMaxEdges]; 1.200 + typedef GrGLEffect INHERITED; 1.201 +}; 1.202 + 1.203 +GrGLConvexPolyEffect::GrGLConvexPolyEffect(const GrBackendEffectFactory& factory, 1.204 + const GrDrawEffect& drawEffect) 1.205 + : INHERITED (factory) { 1.206 + fPrevEdges[0] = SK_ScalarNaN; 1.207 +} 1.208 + 1.209 +void GrGLConvexPolyEffect::emitCode(GrGLShaderBuilder* builder, 1.210 + const GrDrawEffect& drawEffect, 1.211 + EffectKey key, 1.212 + const char* outputColor, 1.213 + const char* inputColor, 1.214 + const TransformedCoordsArray&, 1.215 + const TextureSamplerArray& samplers) { 1.216 + const GrConvexPolyEffect& cpe = drawEffect.castEffect<GrConvexPolyEffect>(); 1.217 + 1.218 + const char *edgeArrayName; 1.219 + fEdgeUniform = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility, 1.220 + kVec3f_GrSLType, 1.221 + "edges", 1.222 + cpe.getEdgeCount(), 1.223 + &edgeArrayName); 1.224 + builder->fsCodeAppend("\t\tfloat alpha = 1.0;\n"); 1.225 + builder->fsCodeAppend("\t\tfloat edge;\n"); 1.226 + const char* fragmentPos = builder->fragmentPosition(); 1.227 + for (int i = 0; i < cpe.getEdgeCount(); ++i) { 1.228 + builder->fsCodeAppendf("\t\tedge = dot(%s[%d], vec3(%s.x, %s.y, 1));\n", 1.229 + edgeArrayName, i, fragmentPos, fragmentPos); 1.230 + if (GrEffectEdgeTypeIsAA(cpe.getEdgeType())) { 1.231 + builder->fsCodeAppend("\t\tedge = clamp(edge, 0.0, 1.0);\n"); 1.232 + } else { 1.233 + builder->fsCodeAppend("\t\tedge = edge >= 0.5 ? 1.0 : 0.0;\n"); 1.234 + } 1.235 + builder->fsCodeAppend("\t\talpha *= edge;\n"); 1.236 + } 1.237 + 1.238 + // Woe is me. See skbug.com/2149. 1.239 + if (kTegra2_GrGLRenderer == builder->ctxInfo().renderer()) { 1.240 + builder->fsCodeAppend("\t\tif (-1.0 == alpha) {\n\t\t\tdiscard;\n\t\t}\n"); 1.241 + } 1.242 + 1.243 + if (GrEffectEdgeTypeIsInverseFill(cpe.getEdgeType())) { 1.244 + builder->fsCodeAppend("\talpha = 1.0 - alpha;\n"); 1.245 + } 1.246 + builder->fsCodeAppendf("\t%s = %s;\n", outputColor, 1.247 + (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str()); 1.248 +} 1.249 + 1.250 +void GrGLConvexPolyEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { 1.251 + const GrConvexPolyEffect& cpe = drawEffect.castEffect<GrConvexPolyEffect>(); 1.252 + size_t byteSize = 3 * cpe.getEdgeCount() * sizeof(SkScalar); 1.253 + if (0 != memcmp(fPrevEdges, cpe.getEdges(), byteSize)) { 1.254 + uman.set3fv(fEdgeUniform, cpe.getEdgeCount(), cpe.getEdges()); 1.255 + memcpy(fPrevEdges, cpe.getEdges(), byteSize); 1.256 + } 1.257 +} 1.258 + 1.259 +GrGLEffect::EffectKey GrGLConvexPolyEffect::GenKey(const GrDrawEffect& drawEffect, 1.260 + const GrGLCaps&) { 1.261 + const GrConvexPolyEffect& cpe = drawEffect.castEffect<GrConvexPolyEffect>(); 1.262 + GR_STATIC_ASSERT(kGrEffectEdgeTypeCnt <= 8); 1.263 + return (cpe.getEdgeCount() << 3) | cpe.getEdgeType(); 1.264 +} 1.265 + 1.266 +////////////////////////////////////////////////////////////////////////////// 1.267 + 1.268 +GrEffectRef* GrConvexPolyEffect::Create(GrEffectEdgeType type, const SkPath& path, const SkVector* offset) { 1.269 + if (kHairlineAA_GrEffectEdgeType == type) { 1.270 + return NULL; 1.271 + } 1.272 + if (path.getSegmentMasks() != SkPath::kLine_SegmentMask || 1.273 + !path.isConvex()) { 1.274 + return NULL; 1.275 + } 1.276 + 1.277 + if (path.countPoints() > kMaxEdges) { 1.278 + return NULL; 1.279 + } 1.280 + 1.281 + SkPoint pts[kMaxEdges]; 1.282 + SkScalar edges[3 * kMaxEdges]; 1.283 + 1.284 + SkPath::Direction dir; 1.285 + SkAssertResult(path.cheapComputeDirection(&dir)); 1.286 + 1.287 + SkVector t; 1.288 + if (NULL == offset) { 1.289 + t.set(0, 0); 1.290 + } else { 1.291 + t = *offset; 1.292 + } 1.293 + 1.294 + int count = path.getPoints(pts, kMaxEdges); 1.295 + int n = 0; 1.296 + for (int lastPt = count - 1, i = 0; i < count; lastPt = i++) { 1.297 + if (pts[lastPt] != pts[i]) { 1.298 + SkVector v = pts[i] - pts[lastPt]; 1.299 + v.normalize(); 1.300 + if (SkPath::kCCW_Direction == dir) { 1.301 + edges[3 * n] = v.fY; 1.302 + edges[3 * n + 1] = -v.fX; 1.303 + } else { 1.304 + edges[3 * n] = -v.fY; 1.305 + edges[3 * n + 1] = v.fX; 1.306 + } 1.307 + SkPoint p = pts[i] + t; 1.308 + edges[3 * n + 2] = -(edges[3 * n] * p.fX + edges[3 * n + 1] * p.fY); 1.309 + ++n; 1.310 + } 1.311 + } 1.312 + if (path.isInverseFillType()) { 1.313 + type = GrInvertEffectEdgeType(type); 1.314 + } 1.315 + return Create(type, n, edges); 1.316 +} 1.317 + 1.318 +GrEffectRef* GrConvexPolyEffect::Create(GrEffectEdgeType edgeType, const SkRect& rect) { 1.319 + if (kHairlineAA_GrEffectEdgeType == edgeType){ 1.320 + return NULL; 1.321 + } 1.322 + return AARectEffect::Create(edgeType, rect); 1.323 +} 1.324 + 1.325 +GrConvexPolyEffect::~GrConvexPolyEffect() {} 1.326 + 1.327 +void GrConvexPolyEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { 1.328 + *validFlags = 0; 1.329 +} 1.330 + 1.331 +const GrBackendEffectFactory& GrConvexPolyEffect::getFactory() const { 1.332 + return GrTBackendEffectFactory<GrConvexPolyEffect>::getInstance(); 1.333 +} 1.334 + 1.335 +GrConvexPolyEffect::GrConvexPolyEffect(GrEffectEdgeType edgeType, int n, const SkScalar edges[]) 1.336 + : fEdgeType(edgeType) 1.337 + , fEdgeCount(n) { 1.338 + // Factory function should have already ensured this. 1.339 + SkASSERT(n <= kMaxEdges); 1.340 + memcpy(fEdges, edges, 3 * n * sizeof(SkScalar)); 1.341 + // Outset the edges by 0.5 so that a pixel with center on an edge is 50% covered in the AA case 1.342 + // and 100% covered in the non-AA case. 1.343 + for (int i = 0; i < n; ++i) { 1.344 + fEdges[3 * i + 2] += SK_ScalarHalf; 1.345 + } 1.346 + this->setWillReadFragmentPosition(); 1.347 +} 1.348 + 1.349 +bool GrConvexPolyEffect::onIsEqual(const GrEffect& other) const { 1.350 + const GrConvexPolyEffect& cpe = CastEffect<GrConvexPolyEffect>(other); 1.351 + // ignore the fact that 0 == -0 and just use memcmp. 1.352 + return (cpe.fEdgeType == fEdgeType && cpe.fEdgeCount == fEdgeCount && 1.353 + 0 == memcmp(cpe.fEdges, fEdges, 3 * fEdgeCount * sizeof(SkScalar))); 1.354 +} 1.355 + 1.356 +////////////////////////////////////////////////////////////////////////////// 1.357 + 1.358 +GR_DEFINE_EFFECT_TEST(GrConvexPolyEffect); 1.359 + 1.360 +GrEffectRef* GrConvexPolyEffect::TestCreate(SkRandom* random, 1.361 + GrContext*, 1.362 + const GrDrawTargetCaps& caps, 1.363 + GrTexture*[]) { 1.364 + int count = random->nextULessThan(kMaxEdges) + 1; 1.365 + SkScalar edges[kMaxEdges * 3]; 1.366 + for (int i = 0; i < 3 * count; ++i) { 1.367 + edges[i] = random->nextSScalar1(); 1.368 + } 1.369 + 1.370 + GrEffectRef* effect; 1.371 + do { 1.372 + GrEffectEdgeType edgeType = static_cast<GrEffectEdgeType>( 1.373 + random->nextULessThan(kGrEffectEdgeTypeCnt)); 1.374 + effect = GrConvexPolyEffect::Create(edgeType, count, edges); 1.375 + } while (NULL == effect); 1.376 + return effect; 1.377 +}