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 "GrAARectRenderer.h" 9#include "GrGpu.h" 10#include "gl/GrGLEffect.h" 11#include "gl/GrGLVertexEffect.h" 12#include "GrTBackendEffectFactory.h" 13#include "SkColorPriv.h" 14#include "effects/GrVertexEffect.h" 15 16/////////////////////////////////////////////////////////////////////////////// 17class GrGLAlignedRectEffect; 18 19// Axis Aligned special case 20class GrAlignedRectEffect : public GrVertexEffect { 21public: 22 static GrEffectRef* Create() { 23 GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ()); 24 gAlignedRectEffect->ref(); 25 return gAlignedRectEffect; 26 } 27 28 virtual ~GrAlignedRectEffect() {} 29 30 static const char* Name() { return "AlignedRectEdge"; } 31 32 virtual void getConstantColorComponents(GrColor* color, 33 uint32_t* validFlags) const SK_OVERRIDE { 34 *validFlags = 0; 35 } 36 37 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 38 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance(); 39 } 40 41 class GLEffect : public GrGLVertexEffect { 42 public: 43 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) 44 : INHERITED (factory) {} 45 46 virtual void emitCode(GrGLFullShaderBuilder* builder, 47 const GrDrawEffect& drawEffect, 48 EffectKey key, 49 const char* outputColor, 50 const char* inputColor, 51 const TransformedCoordsArray&, 52 const TextureSamplerArray& samplers) SK_OVERRIDE { 53 // setup the varying for the Axis aligned rect effect 54 // xy -> interpolated offset 55 // zw -> w/2+0.5, h/2+0.5 56 const char *vsRectName, *fsRectName; 57 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName); 58 const SkString* attr0Name = 59 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); 60 builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str()); 61 62 // TODO: compute all these offsets, spans, and scales in the VS 63 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName); 64 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName); 65 builder->fsCodeAppend("\tfloat outset = 0.5;\n"); 66 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects 67 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range. 68 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n"); 69 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n"); 70 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum 71 // value of coverage that is used. In other words it is the coverage that is 72 // used in the interior of the rect after the ramp. 73 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n"); 74 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n"); 75 76 // Compute the coverage for the rect's width 77 builder->fsCodeAppendf( 78 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName, 79 fsRectName); 80 // Compute the coverage for the rect's height and merge with the width 81 builder->fsCodeAppendf( 82 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n", 83 fsRectName, fsRectName); 84 85 86 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, 87 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str()); 88 } 89 90 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 91 return 0; 92 } 93 94 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {} 95 96 private: 97 typedef GrGLVertexEffect INHERITED; 98 }; 99 100 101private: 102 GrAlignedRectEffect() : GrVertexEffect() { 103 this->addVertexAttrib(kVec4f_GrSLType); 104 } 105 106 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; } 107 108 GR_DECLARE_EFFECT_TEST; 109 110 typedef GrVertexEffect INHERITED; 111}; 112 113 114GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect); 115 116GrEffectRef* GrAlignedRectEffect::TestCreate(SkRandom* random, 117 GrContext* context, 118 const GrDrawTargetCaps&, 119 GrTexture* textures[]) { 120 return GrAlignedRectEffect::Create(); 121} 122 123/////////////////////////////////////////////////////////////////////////////// 124class GrGLRectEffect; 125 126/** 127 * The output of this effect is a modulation of the input color and coverage 128 * for an arbitrarily oriented rect. The rect is specified as: 129 * Center of the rect 130 * Unit vector point down the height of the rect 131 * Half width + 0.5 132 * Half height + 0.5 133 * The center and vector are stored in a vec4 varying ("RectEdge") with the 134 * center in the xy components and the vector in the zw components. 135 * The munged width and height are stored in a vec2 varying ("WidthHeight") 136 * with the width in x and the height in y. 137 */ 138class GrRectEffect : public GrVertexEffect { 139public: 140 static GrEffectRef* Create() { 141 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ()); 142 gRectEffect->ref(); 143 return gRectEffect; 144 } 145 146 virtual ~GrRectEffect() {} 147 148 static const char* Name() { return "RectEdge"; } 149 150 virtual void getConstantColorComponents(GrColor* color, 151 uint32_t* validFlags) const SK_OVERRIDE { 152 *validFlags = 0; 153 } 154 155 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 156 return GrTBackendEffectFactory<GrRectEffect>::getInstance(); 157 } 158 159 class GLEffect : public GrGLVertexEffect { 160 public: 161 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) 162 : INHERITED (factory) {} 163 164 virtual void emitCode(GrGLFullShaderBuilder* builder, 165 const GrDrawEffect& drawEffect, 166 EffectKey key, 167 const char* outputColor, 168 const char* inputColor, 169 const TransformedCoordsArray&, 170 const TextureSamplerArray& samplers) SK_OVERRIDE { 171 // setup the varying for the center point and the unit vector 172 // that points down the height of the rect 173 const char *vsRectEdgeName, *fsRectEdgeName; 174 builder->addVarying(kVec4f_GrSLType, "RectEdge", 175 &vsRectEdgeName, &fsRectEdgeName); 176 const SkString* attr0Name = 177 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); 178 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str()); 179 180 // setup the varying for width/2+.5 and height/2+.5 181 const char *vsWidthHeightName, *fsWidthHeightName; 182 builder->addVarying(kVec2f_GrSLType, "WidthHeight", 183 &vsWidthHeightName, &fsWidthHeightName); 184 const SkString* attr1Name = 185 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]); 186 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str()); 187 188 // TODO: compute all these offsets, spans, and scales in the VS 189 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName); 190 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName); 191 builder->fsCodeAppend("\tfloat outset = 0.5;\n"); 192 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects 193 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range. 194 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n"); 195 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n"); 196 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum 197 // value of coverage that is used. In other words it is the coverage that is 198 // used in the interior of the rect after the ramp. 199 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n"); 200 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n"); 201 202 // Compute the coverage for the rect's width 203 builder->fsCodeAppendf("\tvec2 offset = %s - %s.xy;\n", 204 builder->fragmentPosition(), fsRectEdgeName); 205 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n", 206 fsRectEdgeName, fsRectEdgeName); 207 builder->fsCodeAppendf( 208 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n", 209 fsWidthHeightName); 210 211 // Compute the coverage for the rect's height and merge with the width 212 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n", 213 fsRectEdgeName); 214 builder->fsCodeAppendf( 215 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n", 216 fsWidthHeightName); 217 218 219 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, 220 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str()); 221 } 222 223 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 224 return 0; 225 } 226 227 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {} 228 229 private: 230 typedef GrGLVertexEffect INHERITED; 231 }; 232 233 234private: 235 GrRectEffect() : GrVertexEffect() { 236 this->addVertexAttrib(kVec4f_GrSLType); 237 this->addVertexAttrib(kVec2f_GrSLType); 238 this->setWillReadFragmentPosition(); 239 } 240 241 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; } 242 243 GR_DECLARE_EFFECT_TEST; 244 245 typedef GrVertexEffect INHERITED; 246}; 247 248 249GR_DEFINE_EFFECT_TEST(GrRectEffect); 250 251GrEffectRef* GrRectEffect::TestCreate(SkRandom* random, 252 GrContext* context, 253 const GrDrawTargetCaps&, 254 GrTexture* textures[]) { 255 return GrRectEffect::Create(); 256} 257 258/////////////////////////////////////////////////////////////////////////////// 259 260namespace { 261 262extern const GrVertexAttrib gAARectCoverageAttribs[] = { 263 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 264 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kCoverage_GrVertexAttribBinding}, 265}; 266 267extern const GrVertexAttrib gAARectColorAttribs[] = { 268 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 269 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding}, 270}; 271 272static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) { 273 if (useCoverage) { 274 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs)); 275 } else { 276 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs)); 277 } 278} 279 280static void set_inset_fan(SkPoint* pts, size_t stride, 281 const SkRect& r, SkScalar dx, SkScalar dy) { 282 pts->setRectFan(r.fLeft + dx, r.fTop + dy, 283 r.fRight - dx, r.fBottom - dy, stride); 284} 285 286}; 287 288void GrAARectRenderer::reset() { 289 SkSafeSetNull(fAAFillRectIndexBuffer); 290 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer); 291 SkSafeSetNull(fAABevelStrokeRectIndexBuffer); 292} 293 294static const uint16_t gFillAARectIdx[] = { 295 0, 1, 5, 5, 4, 0, 296 1, 2, 6, 6, 5, 1, 297 2, 3, 7, 7, 6, 2, 298 3, 0, 4, 4, 7, 3, 299 4, 5, 6, 6, 7, 4, 300}; 301 302static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx); 303static const int kVertsPerAAFillRect = 8; 304static const int kNumAAFillRectsInIndexBuffer = 256; 305 306GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) { 307 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect * 308 sizeof(uint16_t) * 309 kNumAAFillRectsInIndexBuffer; 310 311 if (NULL == fAAFillRectIndexBuffer) { 312 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false); 313 if (NULL != fAAFillRectIndexBuffer) { 314 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->map(); 315 bool useTempData = (NULL == data); 316 if (useTempData) { 317 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect); 318 } 319 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) { 320 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around 321 // the inner rect (for AA) and 2 for the inner rect. 322 int baseIdx = i * kIndicesPerAAFillRect; 323 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect); 324 for (int j = 0; j < kIndicesPerAAFillRect; ++j) { 325 data[baseIdx+j] = baseVert + gFillAARectIdx[j]; 326 } 327 } 328 if (useTempData) { 329 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) { 330 SkFAIL("Can't get AA Fill Rect indices into buffer!"); 331 } 332 SkDELETE_ARRAY(data); 333 } else { 334 fAAFillRectIndexBuffer->unmap(); 335 } 336 } 337 } 338 339 return fAAFillRectIndexBuffer; 340} 341 342static const uint16_t gMiterStrokeAARectIdx[] = { 343 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0, 344 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0, 345 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0, 346 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0, 347 348 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4, 349 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4, 350 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4, 351 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4, 352 353 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8, 354 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8, 355 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8, 356 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8, 357}; 358 359/** 360 * As in miter-stroke, index = a + b, and a is the current index, b is the shift 361 * from the first index. The index layout: 362 * outer AA line: 0~3, 4~7 363 * outer edge: 8~11, 12~15 364 * inner edge: 16~19 365 * inner AA line: 20~23 366 * Following comes a bevel-stroke rect and its indices: 367 * 368 * 4 7 369 * ********************************* 370 * * ______________________________ * 371 * * / 12 15 \ * 372 * * / \ * 373 * 0 * |8 16_____________________19 11 | * 3 374 * * | | | | * 375 * * | | **************** | | * 376 * * | | * 20 23 * | | * 377 * * | | * * | | * 378 * * | | * 21 22 * | | * 379 * * | | **************** | | * 380 * * | |____________________| | * 381 * 1 * |9 17 18 10| * 2 382 * * \ / * 383 * * \13 __________________________14/ * 384 * * * 385 * ********************************** 386 * 5 6 387 */ 388static const uint16_t gBevelStrokeAARectIdx[] = { 389 // Draw outer AA, from outer AA line to outer edge, shift is 0. 390 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0, 391 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0, 392 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0, 393 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0, 394 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0, 395 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0, 396 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0, 397 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0, 398 399 // Draw the stroke, from outer edge to inner edge, shift is 8. 400 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8, 401 1 + 8, 5 + 8, 9 + 8, 402 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8, 403 6 + 8, 2 + 8, 10 + 8, 404 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8, 405 3 + 8, 7 + 8, 11 + 8, 406 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8, 407 4 + 8, 0 + 8, 8 + 8, 408 409 // Draw the inner AA, from inner edge to inner AA line, shift is 16. 410 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16, 411 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16, 412 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16, 413 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16, 414}; 415 416int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) { 417 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) : 418 SK_ARRAY_COUNT(gBevelStrokeAARectIdx); 419} 420 421GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) { 422 if (miterStroke) { 423 if (NULL == fAAMiterStrokeRectIndexBuffer) { 424 fAAMiterStrokeRectIndexBuffer = 425 gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false); 426 if (NULL != fAAMiterStrokeRectIndexBuffer) { 427#ifdef SK_DEBUG 428 bool updated = 429#endif 430 fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx, 431 sizeof(gMiterStrokeAARectIdx)); 432 GR_DEBUGASSERT(updated); 433 } 434 } 435 return fAAMiterStrokeRectIndexBuffer; 436 } else { 437 if (NULL == fAABevelStrokeRectIndexBuffer) { 438 fAABevelStrokeRectIndexBuffer = 439 gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false); 440 if (NULL != fAABevelStrokeRectIndexBuffer) { 441#ifdef SK_DEBUG 442 bool updated = 443#endif 444 fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx, 445 sizeof(gBevelStrokeAARectIdx)); 446 GR_DEBUGASSERT(updated); 447 } 448 } 449 return fAABevelStrokeRectIndexBuffer; 450 } 451} 452 453void GrAARectRenderer::geometryFillAARect(GrGpu* gpu, 454 GrDrawTarget* target, 455 const SkRect& rect, 456 const SkMatrix& combinedMatrix, 457 const SkRect& devRect, 458 bool useVertexCoverage) { 459 GrDrawState* drawState = target->drawState(); 460 461 set_aa_rect_vertex_attributes(drawState, useVertexCoverage); 462 463 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0); 464 if (!geo.succeeded()) { 465 GrPrintf("Failed to get space for vertices!\n"); 466 return; 467 } 468 469 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu); 470 if (NULL == indexBuffer) { 471 GrPrintf("Failed to create index buffer!\n"); 472 return; 473 } 474 475 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); 476 size_t vsize = drawState->getVertexSize(); 477 SkASSERT(sizeof(SkPoint) + sizeof(GrColor) == vsize); 478 479 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts); 480 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vsize); 481 482 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1); 483 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height()); 484 485 if (combinedMatrix.rectStaysRect()) { 486 // Temporarily #if'ed out. We don't want to pass in the devRect but 487 // right now it is computed in GrContext::apply_aa_to_rect and we don't 488 // want to throw away the work 489#if 0 490 SkRect devRect; 491 combinedMatrix.mapRect(&devRect, rect); 492#endif 493 494 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf); 495 set_inset_fan(fan1Pos, vsize, devRect, inset, inset); 496 } else { 497 // compute transformed (1, 0) and (0, 1) vectors 498 SkVector vec[2] = { 499 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] }, 500 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] } 501 }; 502 503 vec[0].normalize(); 504 vec[0].scale(SK_ScalarHalf); 505 vec[1].normalize(); 506 vec[1].scale(SK_ScalarHalf); 507 508 // create the rotated rect 509 fan0Pos->setRectFan(rect.fLeft, rect.fTop, 510 rect.fRight, rect.fBottom, vsize); 511 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4); 512 513 // Now create the inset points and then outset the original 514 // rotated points 515 516 // TL 517 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) = 518 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1]; 519 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1]; 520 // BL 521 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) = 522 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1]; 523 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1]; 524 // BR 525 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) = 526 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1]; 527 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1]; 528 // TR 529 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) = 530 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1]; 531 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1]; 532 } 533 534 verts += sizeof(SkPoint); 535 for (int i = 0; i < 4; ++i) { 536 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; 537 } 538 539 int scale; 540 if (inset < SK_ScalarHalf) { 541 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); 542 SkASSERT(scale >= 0 && scale <= 255); 543 } else { 544 scale = 0xff; 545 } 546 547 GrColor innerColor; 548 if (useVertexCoverage) { 549 innerColor = GrColorPackRGBA(scale, scale, scale, scale); 550 } else { 551 if (0xff == scale) { 552 innerColor = target->getDrawState().getColor(); 553 } else { 554 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale); 555 } 556 } 557 558 verts += 4 * vsize; 559 for (int i = 0; i < 4; ++i) { 560 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; 561 } 562 563 target->setIndexSourceToBuffer(indexBuffer); 564 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 565 kVertsPerAAFillRect, 566 kIndicesPerAAFillRect); 567 target->resetIndexSource(); 568} 569 570namespace { 571 572// Rotated 573struct RectVertex { 574 SkPoint fPos; 575 SkPoint fCenter; 576 SkPoint fDir; 577 SkPoint fWidthHeight; 578}; 579 580// Rotated 581extern const GrVertexAttrib gAARectVertexAttribs[] = { 582 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding }, 583 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding }, 584 { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kEffect_GrVertexAttribBinding } 585}; 586 587// Axis Aligned 588struct AARectVertex { 589 SkPoint fPos; 590 SkPoint fOffset; 591 SkPoint fWidthHeight; 592}; 593 594// Axis Aligned 595extern const GrVertexAttrib gAAAARectVertexAttribs[] = { 596 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding }, 597 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding }, 598}; 599 600}; 601 602void GrAARectRenderer::shaderFillAARect(GrGpu* gpu, 603 GrDrawTarget* target, 604 const SkRect& rect, 605 const SkMatrix& combinedMatrix) { 606 GrDrawState* drawState = target->drawState(); 607 608 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY()); 609 combinedMatrix.mapPoints(¢er, 1); 610 611 // compute transformed (0, 1) vector 612 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }; 613 dir.normalize(); 614 615 // compute transformed (width, 0) and (0, height) vectors 616 SkVector vec[2] = { 617 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] }, 618 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] } 619 }; 620 621 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf; 622 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf; 623 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs)); 624 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize()); 625 626 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); 627 if (!geo.succeeded()) { 628 GrPrintf("Failed to get space for vertices!\n"); 629 return; 630 } 631 632 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices()); 633 634 GrEffectRef* effect = GrRectEffect::Create(); 635 static const int kRectAttrIndex = 1; 636 static const int kWidthIndex = 2; 637 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref(); 638 639 for (int i = 0; i < 4; ++i) { 640 verts[i].fCenter = center; 641 verts[i].fDir = dir; 642 verts[i].fWidthHeight.fX = newWidth; 643 verts[i].fWidthHeight.fY = newHeight; 644 } 645 646 SkRect devRect; 647 combinedMatrix.mapRect(&devRect, rect); 648 649 SkRect devBounds = { 650 devRect.fLeft - SK_ScalarHalf, 651 devRect.fTop - SK_ScalarHalf, 652 devRect.fRight + SK_ScalarHalf, 653 devRect.fBottom + SK_ScalarHalf 654 }; 655 656 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop); 657 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom); 658 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom); 659 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop); 660 661 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer()); 662 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6); 663 target->resetIndexSource(); 664} 665 666void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu, 667 GrDrawTarget* target, 668 const SkRect& rect, 669 const SkMatrix& combinedMatrix) { 670 GrDrawState* drawState = target->drawState(); 671 SkASSERT(combinedMatrix.rectStaysRect()); 672 673 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs)); 674 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize()); 675 676 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); 677 if (!geo.succeeded()) { 678 GrPrintf("Failed to get space for vertices!\n"); 679 return; 680 } 681 682 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices()); 683 684 GrEffectRef* effect = GrAlignedRectEffect::Create(); 685 static const int kOffsetIndex = 1; 686 drawState->addCoverageEffect(effect, kOffsetIndex)->unref(); 687 688 SkRect devRect; 689 combinedMatrix.mapRect(&devRect, rect); 690 691 SkRect devBounds = { 692 devRect.fLeft - SK_ScalarHalf, 693 devRect.fTop - SK_ScalarHalf, 694 devRect.fRight + SK_ScalarHalf, 695 devRect.fBottom + SK_ScalarHalf 696 }; 697 698 SkPoint widthHeight = { 699 SkScalarHalf(devRect.width()) + SK_ScalarHalf, 700 SkScalarHalf(devRect.height()) + SK_ScalarHalf 701 }; 702 703 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop); 704 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY); 705 verts[0].fWidthHeight = widthHeight; 706 707 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom); 708 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY); 709 verts[1].fWidthHeight = widthHeight; 710 711 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom); 712 verts[2].fOffset = widthHeight; 713 verts[2].fWidthHeight = widthHeight; 714 715 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop); 716 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY); 717 verts[3].fWidthHeight = widthHeight; 718 719 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer()); 720 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6); 721 target->resetIndexSource(); 722} 723 724void GrAARectRenderer::strokeAARect(GrGpu* gpu, 725 GrDrawTarget* target, 726 const SkRect& rect, 727 const SkMatrix& combinedMatrix, 728 const SkRect& devRect, 729 const SkStrokeRec& stroke, 730 bool useVertexCoverage) { 731 SkVector devStrokeSize; 732 SkScalar width = stroke.getWidth(); 733 if (width > 0) { 734 devStrokeSize.set(width, width); 735 combinedMatrix.mapVectors(&devStrokeSize, 1); 736 devStrokeSize.setAbs(devStrokeSize); 737 } else { 738 devStrokeSize.set(SK_Scalar1, SK_Scalar1); 739 } 740 741 const SkScalar dx = devStrokeSize.fX; 742 const SkScalar dy = devStrokeSize.fY; 743 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf); 744 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf); 745 746 // Temporarily #if'ed out. We don't want to pass in the devRect but 747 // right now it is computed in GrContext::apply_aa_to_rect and we don't 748 // want to throw away the work 749#if 0 750 SkRect devRect; 751 combinedMatrix.mapRect(&devRect, rect); 752#endif 753 754 SkScalar spare; 755 { 756 SkScalar w = devRect.width() - dx; 757 SkScalar h = devRect.height() - dy; 758 spare = SkTMin(w, h); 759 } 760 761 SkRect devOutside(devRect); 762 devOutside.outset(rx, ry); 763 764 bool miterStroke = true; 765 // small miter limit means right angles show bevel... 766 if (stroke.getJoin() != SkPaint::kMiter_Join || stroke.getMiter() < SK_ScalarSqrt2) { 767 miterStroke = false; 768 } 769 770 if (spare <= 0 && miterStroke) { 771 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), 772 devOutside, useVertexCoverage); 773 return; 774 } 775 776 SkRect devInside(devRect); 777 devInside.inset(rx, ry); 778 779 SkRect devOutsideAssist(devRect); 780 781 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist) 782 // to draw the outer of the rect. Because there are 8 vertices on the outer 783 // edge, while vertex number of inner edge is 4, the same as miter-stroke. 784 if (!miterStroke) { 785 devOutside.inset(0, ry); 786 devOutsideAssist.outset(0, ry); 787 } 788 789 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, 790 devInside, useVertexCoverage, miterStroke); 791} 792 793void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu, 794 GrDrawTarget* target, 795 const SkRect& devOutside, 796 const SkRect& devOutsideAssist, 797 const SkRect& devInside, 798 bool useVertexCoverage, 799 bool miterStroke) { 800 GrDrawState* drawState = target->drawState(); 801 802 set_aa_rect_vertex_attributes(drawState, useVertexCoverage); 803 804 int innerVertexNum = 4; 805 int outerVertexNum = miterStroke ? 4 : 8; 806 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2; 807 808 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0); 809 if (!geo.succeeded()) { 810 GrPrintf("Failed to get space for vertices!\n"); 811 return; 812 } 813 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke); 814 if (NULL == indexBuffer) { 815 GrPrintf("Failed to create index buffer!\n"); 816 return; 817 } 818 819 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); 820 size_t vsize = drawState->getVertexSize(); 821 SkASSERT(sizeof(SkPoint) + sizeof(GrColor) == vsize); 822 823 // We create vertices for four nested rectangles. There are two ramps from 0 to full 824 // coverage, one on the exterior of the stroke and the other on the interior. 825 // The following pointers refer to the four rects, from outermost to innermost. 826 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts); 827 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vsize); 828 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vsize); 829 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vsize); 830 831#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX 832 // TODO: this only really works if the X & Y margins are the same all around 833 // the rect 834 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight); 835 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft); 836 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop); 837 if (miterStroke) { 838 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom); 839 } else { 840 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom); 841 } 842 SkASSERT(inset >= 0); 843#else 844 SkScalar inset = SK_ScalarHalf; 845#endif 846 847 if (miterStroke) { 848 // outermost 849 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); 850 // inner two 851 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset); 852 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset); 853 // innermost 854 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf); 855 } else { 856 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vsize); 857 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vsize); 858 // outermost 859 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); 860 set_inset_fan(fan0AssistPos, vsize, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf); 861 // outer one of the inner two 862 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset); 863 set_inset_fan(fan1AssistPos, vsize, devOutsideAssist, inset, inset); 864 // inner one of the inner two 865 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset); 866 // innermost 867 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf); 868 } 869 870 // The outermost rect has 0 coverage 871 verts += sizeof(SkPoint); 872 for (int i = 0; i < outerVertexNum; ++i) { 873 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; 874 } 875 876 int scale; 877 if (inset < SK_ScalarHalf) { 878 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); 879 SkASSERT(scale >= 0 && scale <= 255); 880 } else { 881 scale = 0xff; 882 } 883 884 // The inner two rects have full coverage 885 GrColor innerColor; 886 if (useVertexCoverage) { 887 innerColor = GrColorPackRGBA(scale, scale, scale, scale); 888 } else { 889 if (0xff == scale) { 890 innerColor = target->getDrawState().getColor(); 891 } else { 892 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale); 893 } 894 } 895 896 verts += outerVertexNum * vsize; 897 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) { 898 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; 899 } 900 901 // The innermost rect has 0 coverage 902 verts += (outerVertexNum + innerVertexNum) * vsize; 903 for (int i = 0; i < innerVertexNum; ++i) { 904 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; 905 } 906 907 target->setIndexSourceToBuffer(indexBuffer); 908 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 909 totalVertexNum, aaStrokeRectIndexCount(miterStroke)); 910} 911 912void GrAARectRenderer::fillAANestedRects(GrGpu* gpu, 913 GrDrawTarget* target, 914 const SkRect rects[2], 915 const SkMatrix& combinedMatrix, 916 bool useVertexCoverage) { 917 SkASSERT(combinedMatrix.rectStaysRect()); 918 SkASSERT(!rects[1].isEmpty()); 919 920 SkRect devOutside, devOutsideAssist, devInside; 921 combinedMatrix.mapRect(&devOutside, rects[0]); 922 // can't call mapRect for devInside since it calls sort 923 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2); 924 925 if (devInside.isEmpty()) { 926 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage); 927 return; 928 } 929 930 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, 931 devInside, useVertexCoverage, true); 932} 933