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 "GrRefCnt.h" 10 #include "GrGpu.h" 11 #include "gl/GrGLEffect.h" 12 #include "GrTBackendEffectFactory.h" 13 #include "SkColorPriv.h" 14 15 SK_DEFINE_INST_COUNT(GrAARectRenderer) 16 17 /////////////////////////////////////////////////////////////////////////////// 18 class GrGLAlignedRectEffect; 19 20 // Axis Aligned special case 21 class GrAlignedRectEffect : public GrEffect { 22 public: 23 static GrEffectRef* Create() { 24 GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ()); 25 gAlignedRectEffect->ref(); 26 return gAlignedRectEffect; 27 } 28 29 virtual ~GrAlignedRectEffect() {} 30 31 static const char* Name() { return "AlignedRectEdge"; } 32 33 virtual void getConstantColorComponents(GrColor* color, 34 uint32_t* validFlags) const SK_OVERRIDE { 35 *validFlags = 0; 36 } 37 38 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 39 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance(); 40 } 41 42 class GLEffect : public GrGLEffect { 43 public: 44 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) 45 : INHERITED (factory) {} 46 47 virtual void emitCode(GrGLShaderBuilder* builder, 48 const GrDrawEffect& drawEffect, 49 EffectKey key, 50 const char* outputColor, 51 const char* inputColor, 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 SkString modulate; 86 GrGLSLModulatef<4>(&modulate, inputColor, "coverage"); 87 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.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 GrGLEffect INHERITED; 98 }; 99 100 101 private: 102 GrAlignedRectEffect() : GrEffect() { 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 GrEffect INHERITED; 111 }; 112 113 114 GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect); 115 116 GrEffectRef* GrAlignedRectEffect::TestCreate(SkMWCRandom* random, 117 GrContext* context, 118 const GrDrawTargetCaps&, 119 GrTexture* textures[]) { 120 return GrAlignedRectEffect::Create(); 121 } 122 123 /////////////////////////////////////////////////////////////////////////////// 124 class 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 */ 138 class GrRectEffect : public GrEffect { 139 public: 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 GrGLEffect { 160 public: 161 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) 162 : INHERITED (factory) {} 163 164 virtual void emitCode(GrGLShaderBuilder* builder, 165 const GrDrawEffect& drawEffect, 166 EffectKey key, 167 const char* outputColor, 168 const char* inputColor, 169 const TextureSamplerArray& samplers) SK_OVERRIDE { 170 // setup the varying for the center point and the unit vector 171 // that points down the height of the rect 172 const char *vsRectEdgeName, *fsRectEdgeName; 173 builder->addVarying(kVec4f_GrSLType, "RectEdge", 174 &vsRectEdgeName, &fsRectEdgeName); 175 const SkString* attr0Name = 176 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); 177 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str()); 178 179 // setup the varying for width/2+.5 and height/2+.5 180 const char *vsWidthHeightName, *fsWidthHeightName; 181 builder->addVarying(kVec2f_GrSLType, "WidthHeight", 182 &vsWidthHeightName, &fsWidthHeightName); 183 const SkString* attr1Name = 184 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]); 185 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str()); 186 187 // TODO: compute all these offsets, spans, and scales in the VS 188 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName); 189 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName); 190 builder->fsCodeAppend("\tfloat outset = 0.5;\n"); 191 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects 192 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range. 193 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n"); 194 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n"); 195 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum 196 // value of coverage that is used. In other words it is the coverage that is 197 // used in the interior of the rect after the ramp. 198 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n"); 199 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n"); 200 201 // Compute the coverage for the rect's width 202 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n", 203 builder->fragmentPosition(), fsRectEdgeName); 204 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n", 205 fsRectEdgeName, fsRectEdgeName); 206 builder->fsCodeAppendf( 207 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n", 208 fsWidthHeightName); 209 210 // Compute the coverage for the rect's height and merge with the width 211 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n", 212 fsRectEdgeName); 213 builder->fsCodeAppendf( 214 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n", 215 fsWidthHeightName); 216 217 SkString modulate; 218 GrGLSLModulatef<4>(&modulate, inputColor, "coverage"); 219 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()); 220 } 221 222 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 223 return 0; 224 } 225 226 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {} 227 228 private: 229 typedef GrGLEffect INHERITED; 230 }; 231 232 233 private: 234 GrRectEffect() : GrEffect() { 235 this->addVertexAttrib(kVec4f_GrSLType); 236 this->addVertexAttrib(kVec2f_GrSLType); 237 this->setWillReadFragmentPosition(); 238 } 239 240 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; } 241 242 GR_DECLARE_EFFECT_TEST; 243 244 typedef GrEffect INHERITED; 245 }; 246 247 248 GR_DEFINE_EFFECT_TEST(GrRectEffect); 249 250 GrEffectRef* GrRectEffect::TestCreate(SkMWCRandom* random, 251 GrContext* context, 252 const GrDrawTargetCaps&, 253 GrTexture* textures[]) { 254 return GrRectEffect::Create(); 255 } 256 257 /////////////////////////////////////////////////////////////////////////////// 258 259 namespace { 260 261 extern const GrVertexAttrib gAARectCoverageAttribs[] = { 262 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 263 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding}, 264 }; 265 266 extern const GrVertexAttrib gAARectColorAttribs[] = { 267 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 268 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding}, 269 }; 270 271 static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) { 272 if (useCoverage) { 273 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs)); 274 } else { 275 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs)); 276 } 277 } 278 279 static void set_inset_fan(GrPoint* pts, size_t stride, 280 const SkRect& r, SkScalar dx, SkScalar dy) { 281 pts->setRectFan(r.fLeft + dx, r.fTop + dy, 282 r.fRight - dx, r.fBottom - dy, stride); 283 } 284 285 }; 286 287 void GrAARectRenderer::reset() { 288 GrSafeSetNull(fAAFillRectIndexBuffer); 289 GrSafeSetNull(fAAStrokeRectIndexBuffer); 290 } 291 292 static const uint16_t gFillAARectIdx[] = { 293 0, 1, 5, 5, 4, 0, 294 1, 2, 6, 6, 5, 1, 295 2, 3, 7, 7, 6, 2, 296 3, 0, 4, 4, 7, 3, 297 4, 5, 6, 6, 7, 4, 298 }; 299 300 static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx); 301 static const int kVertsPerAAFillRect = 8; 302 static const int kNumAAFillRectsInIndexBuffer = 256; 303 304 GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) { 305 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect * 306 sizeof(uint16_t) * 307 kNumAAFillRectsInIndexBuffer; 308 309 if (NULL == fAAFillRectIndexBuffer) { 310 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false); 311 if (NULL != fAAFillRectIndexBuffer) { 312 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock(); 313 bool useTempData = (NULL == data); 314 if (useTempData) { 315 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect); 316 } 317 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) { 318 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around 319 // the inner rect (for AA) and 2 for the inner rect. 320 int baseIdx = i * kIndicesPerAAFillRect; 321 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect); 322 for (int j = 0; j < kIndicesPerAAFillRect; ++j) { 323 data[baseIdx+j] = baseVert + gFillAARectIdx[j]; 324 } 325 } 326 if (useTempData) { 327 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) { 328 GrCrash("Can't get AA Fill Rect indices into buffer!"); 329 } 330 SkDELETE_ARRAY(data); 331 } else { 332 fAAFillRectIndexBuffer->unlock(); 333 } 334 } 335 } 336 337 return fAAFillRectIndexBuffer; 338 } 339 340 static const uint16_t gStrokeAARectIdx[] = { 341 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0, 342 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0, 343 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0, 344 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0, 345 346 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4, 347 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4, 348 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4, 349 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4, 350 351 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8, 352 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8, 353 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8, 354 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8, 355 }; 356 357 int GrAARectRenderer::aaStrokeRectIndexCount() { 358 return GR_ARRAY_COUNT(gStrokeAARectIdx); 359 } 360 361 GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) { 362 if (NULL == fAAStrokeRectIndexBuffer) { 363 fAAStrokeRectIndexBuffer = 364 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false); 365 if (NULL != fAAStrokeRectIndexBuffer) { 366 #if GR_DEBUG 367 bool updated = 368 #endif 369 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx, 370 sizeof(gStrokeAARectIdx)); 371 GR_DEBUGASSERT(updated); 372 } 373 } 374 return fAAStrokeRectIndexBuffer; 375 } 376 377 void GrAARectRenderer::geometryFillAARect(GrGpu* gpu, 378 GrDrawTarget* target, 379 const SkRect& rect, 380 const SkMatrix& combinedMatrix, 381 const SkRect& devRect, 382 bool useVertexCoverage) { 383 GrDrawState* drawState = target->drawState(); 384 385 set_aa_rect_vertex_attributes(drawState, useVertexCoverage); 386 387 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0); 388 if (!geo.succeeded()) { 389 GrPrintf("Failed to get space for vertices!\n"); 390 return; 391 } 392 393 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu); 394 if (NULL == indexBuffer) { 395 GrPrintf("Failed to create index buffer!\n"); 396 return; 397 } 398 399 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); 400 size_t vsize = drawState->getVertexSize(); 401 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize); 402 403 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); 404 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); 405 406 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1); 407 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height()); 408 409 if (combinedMatrix.rectStaysRect()) { 410 // Temporarily #if'ed out. We don't want to pass in the devRect but 411 // right now it is computed in GrContext::apply_aa_to_rect and we don't 412 // want to throw away the work 413 #if 0 414 SkRect devRect; 415 combinedMatrix.mapRect(&devRect, rect); 416 #endif 417 418 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf); 419 set_inset_fan(fan1Pos, vsize, devRect, inset, inset); 420 } else { 421 // compute transformed (1, 0) and (0, 1) vectors 422 SkVector vec[2] = { 423 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] }, 424 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] } 425 }; 426 427 vec[0].normalize(); 428 vec[0].scale(SK_ScalarHalf); 429 vec[1].normalize(); 430 vec[1].scale(SK_ScalarHalf); 431 432 // create the rotated rect 433 fan0Pos->setRectFan(rect.fLeft, rect.fTop, 434 rect.fRight, rect.fBottom, vsize); 435 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4); 436 437 // Now create the inset points and then outset the original 438 // rotated points 439 440 // TL 441 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) = 442 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1]; 443 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1]; 444 // BL 445 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) = 446 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1]; 447 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1]; 448 // BR 449 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) = 450 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1]; 451 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1]; 452 // TR 453 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) = 454 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1]; 455 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1]; 456 } 457 458 verts += sizeof(GrPoint); 459 for (int i = 0; i < 4; ++i) { 460 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; 461 } 462 463 int scale; 464 if (inset < SK_ScalarHalf) { 465 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); 466 SkASSERT(scale >= 0 && scale <= 255); 467 } else { 468 scale = 0xff; 469 } 470 471 GrColor innerColor; 472 if (useVertexCoverage) { 473 innerColor = GrColorPackRGBA(scale, scale, scale, scale); 474 } else { 475 if (0xff == scale) { 476 innerColor = target->getDrawState().getColor(); 477 } else { 478 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale); 479 } 480 } 481 482 verts += 4 * vsize; 483 for (int i = 0; i < 4; ++i) { 484 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; 485 } 486 487 target->setIndexSourceToBuffer(indexBuffer); 488 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 489 kVertsPerAAFillRect, 490 kIndicesPerAAFillRect); 491 target->resetIndexSource(); 492 } 493 494 namespace { 495 496 // Rotated 497 struct RectVertex { 498 GrPoint fPos; 499 GrPoint fCenter; 500 GrPoint fDir; 501 GrPoint fWidthHeight; 502 }; 503 504 // Rotated 505 extern const GrVertexAttrib gAARectVertexAttribs[] = { 506 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding }, 507 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding }, 508 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding } 509 }; 510 511 // Axis Aligned 512 struct AARectVertex { 513 GrPoint fPos; 514 GrPoint fOffset; 515 GrPoint fWidthHeight; 516 }; 517 518 // Axis Aligned 519 extern const GrVertexAttrib gAAAARectVertexAttribs[] = { 520 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding }, 521 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding }, 522 }; 523 524 }; 525 526 void GrAARectRenderer::shaderFillAARect(GrGpu* gpu, 527 GrDrawTarget* target, 528 const SkRect& rect, 529 const SkMatrix& combinedMatrix) { 530 GrDrawState* drawState = target->drawState(); 531 532 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY()); 533 combinedMatrix.mapPoints(¢er, 1); 534 535 // compute transformed (0, 1) vector 536 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }; 537 dir.normalize(); 538 539 // compute transformed (width, 0) and (0, height) vectors 540 SkVector vec[2] = { 541 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] }, 542 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] } 543 }; 544 545 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf; 546 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf; 547 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs)); 548 GrAssert(sizeof(RectVertex) == drawState->getVertexSize()); 549 550 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); 551 if (!geo.succeeded()) { 552 GrPrintf("Failed to get space for vertices!\n"); 553 return; 554 } 555 556 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices()); 557 558 GrEffectRef* effect = GrRectEffect::Create(); 559 static const int kRectAttrIndex = 1; 560 static const int kWidthIndex = 2; 561 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref(); 562 563 for (int i = 0; i < 4; ++i) { 564 verts[i].fCenter = center; 565 verts[i].fDir = dir; 566 verts[i].fWidthHeight.fX = newWidth; 567 verts[i].fWidthHeight.fY = newHeight; 568 } 569 570 SkRect devRect; 571 combinedMatrix.mapRect(&devRect, rect); 572 573 SkRect devBounds = { 574 devRect.fLeft - SK_ScalarHalf, 575 devRect.fTop - SK_ScalarHalf, 576 devRect.fRight + SK_ScalarHalf, 577 devRect.fBottom + SK_ScalarHalf 578 }; 579 580 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop); 581 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom); 582 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom); 583 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop); 584 585 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer()); 586 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6); 587 target->resetIndexSource(); 588 } 589 590 void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu, 591 GrDrawTarget* target, 592 const SkRect& rect, 593 const SkMatrix& combinedMatrix) { 594 GrDrawState* drawState = target->drawState(); 595 SkASSERT(combinedMatrix.rectStaysRect()); 596 597 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs)); 598 GrAssert(sizeof(AARectVertex) == drawState->getVertexSize()); 599 600 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); 601 if (!geo.succeeded()) { 602 GrPrintf("Failed to get space for vertices!\n"); 603 return; 604 } 605 606 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices()); 607 608 GrEffectRef* effect = GrAlignedRectEffect::Create(); 609 static const int kOffsetIndex = 1; 610 drawState->addCoverageEffect(effect, kOffsetIndex)->unref(); 611 612 SkRect devRect; 613 combinedMatrix.mapRect(&devRect, rect); 614 615 SkRect devBounds = { 616 devRect.fLeft - SK_ScalarHalf, 617 devRect.fTop - SK_ScalarHalf, 618 devRect.fRight + SK_ScalarHalf, 619 devRect.fBottom + SK_ScalarHalf 620 }; 621 622 GrPoint widthHeight = { 623 SkScalarHalf(devRect.width()) + SK_ScalarHalf, 624 SkScalarHalf(devRect.height()) + SK_ScalarHalf 625 }; 626 627 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop); 628 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY); 629 verts[0].fWidthHeight = widthHeight; 630 631 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom); 632 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY); 633 verts[1].fWidthHeight = widthHeight; 634 635 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom); 636 verts[2].fOffset = widthHeight; 637 verts[2].fWidthHeight = widthHeight; 638 639 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop); 640 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY); 641 verts[3].fWidthHeight = widthHeight; 642 643 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer()); 644 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6); 645 target->resetIndexSource(); 646 } 647 648 void GrAARectRenderer::strokeAARect(GrGpu* gpu, 649 GrDrawTarget* target, 650 const SkRect& rect, 651 const SkMatrix& combinedMatrix, 652 const SkRect& devRect, 653 SkScalar width, 654 bool useVertexCoverage) { 655 GrVec devStrokeSize; 656 if (width > 0) { 657 devStrokeSize.set(width, width); 658 combinedMatrix.mapVectors(&devStrokeSize, 1); 659 devStrokeSize.setAbs(devStrokeSize); 660 } else { 661 devStrokeSize.set(SK_Scalar1, SK_Scalar1); 662 } 663 664 const SkScalar dx = devStrokeSize.fX; 665 const SkScalar dy = devStrokeSize.fY; 666 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf); 667 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf); 668 669 // Temporarily #if'ed out. We don't want to pass in the devRect but 670 // right now it is computed in GrContext::apply_aa_to_rect and we don't 671 // want to throw away the work 672 #if 0 673 SkRect devRect; 674 combinedMatrix.mapRect(&devRect, rect); 675 #endif 676 677 SkScalar spare; 678 { 679 SkScalar w = devRect.width() - dx; 680 SkScalar h = devRect.height() - dy; 681 spare = GrMin(w, h); 682 } 683 684 SkRect devOutside(devRect); 685 devOutside.outset(rx, ry); 686 687 if (spare <= 0) { 688 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), 689 devOutside, useVertexCoverage); 690 return; 691 } 692 693 SkRect devInside(devRect); 694 devInside.inset(rx, ry); 695 696 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage); 697 } 698 699 void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu, 700 GrDrawTarget* target, 701 const SkRect& devOutside, 702 const SkRect& devInside, 703 bool useVertexCoverage) { 704 GrDrawState* drawState = target->drawState(); 705 706 set_aa_rect_vertex_attributes(drawState, useVertexCoverage); 707 708 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); 709 if (!geo.succeeded()) { 710 GrPrintf("Failed to get space for vertices!\n"); 711 return; 712 } 713 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu); 714 if (NULL == indexBuffer) { 715 GrPrintf("Failed to create index buffer!\n"); 716 return; 717 } 718 719 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); 720 size_t vsize = drawState->getVertexSize(); 721 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize); 722 723 // We create vertices for four nested rectangles. There are two ramps from 0 to full 724 // coverage, one on the exterior of the stroke and the other on the interior. 725 // The following pointers refer to the four rects, from outermost to innermost. 726 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); 727 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); 728 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize); 729 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize); 730 731 #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX 732 // TODO: this only really works if the X & Y margins are the same all around 733 // the rect 734 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight); 735 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft); 736 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop); 737 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom); 738 SkASSERT(inset >= 0); 739 #else 740 SkScalar inset = SK_ScalarHalf; 741 #endif 742 743 // outermost 744 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); 745 // inner two 746 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset); 747 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset); 748 // innermost 749 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf); 750 751 // The outermost rect has 0 coverage 752 verts += sizeof(GrPoint); 753 for (int i = 0; i < 4; ++i) { 754 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; 755 } 756 757 int scale; 758 if (inset < SK_ScalarHalf) { 759 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); 760 SkASSERT(scale >= 0 && scale <= 255); 761 } else { 762 scale = 0xff; 763 } 764 765 // The inner two rects have full coverage 766 GrColor innerColor; 767 if (useVertexCoverage) { 768 innerColor = GrColorPackRGBA(scale, scale, scale, scale); 769 } else { 770 if (0xff == scale) { 771 innerColor = target->getDrawState().getColor(); 772 } else { 773 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale); 774 } 775 } 776 777 verts += 4 * vsize; 778 for (int i = 0; i < 8; ++i) { 779 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; 780 } 781 782 // The innermost rect has 0 coverage 783 verts += 8 * vsize; 784 for (int i = 0; i < 4; ++i) { 785 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; 786 } 787 788 target->setIndexSourceToBuffer(indexBuffer); 789 target->drawIndexed(kTriangles_GrPrimitiveType, 790 0, 0, 16, aaStrokeRectIndexCount()); 791 } 792 793 void GrAARectRenderer::fillAANestedRects(GrGpu* gpu, 794 GrDrawTarget* target, 795 const SkRect rects[2], 796 const SkMatrix& combinedMatrix, 797 bool useVertexCoverage) { 798 SkASSERT(combinedMatrix.rectStaysRect()); 799 SkASSERT(!rects[1].isEmpty()); 800 801 SkRect devOutside, devInside; 802 combinedMatrix.mapRect(&devOutside, rects[0]); 803 // can't call mapRect for devInside since it calls sort 804 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2); 805 806 if (devInside.isEmpty()) { 807 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage); 808 return; 809 } 810 811 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage); 812 } 813