Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/gpu/GrOvalRenderer.cpp

Issue 13852049: Add GPU support for roundrects (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Add oval check to SkCanvas Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/gpu/GrContext.cpp ('k') | src/gpu/SkGpuDevice.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "GrOvalRenderer.h" 8 #include "GrOvalRenderer.h"
9 9
10 #include "GrEffect.h" 10 #include "GrEffect.h"
11 #include "gl/GrGLEffect.h" 11 #include "gl/GrGLEffect.h"
12 #include "gl/GrGLSL.h" 12 #include "gl/GrGLSL.h"
13 #include "GrTBackendEffectFactory.h" 13 #include "GrTBackendEffectFactory.h"
14 14
15 #include "GrDrawState.h" 15 #include "GrDrawState.h"
16 #include "GrDrawTarget.h" 16 #include "GrDrawTarget.h"
17 #include "GrGpu.h"
18
19 #include "SkRRect.h"
17 #include "SkStrokeRec.h" 20 #include "SkStrokeRec.h"
18 21
19 SK_DEFINE_INST_COUNT(GrOvalRenderer) 22 SK_DEFINE_INST_COUNT(GrOvalRenderer)
20 23
21 namespace { 24 namespace {
22 25
23 struct CircleVertex { 26 struct CircleVertex {
24 GrPoint fPos; 27 GrPoint fPos;
25 GrPoint fOffset; 28 GrPoint fOffset;
26 SkScalar fOuterRadius; 29 SkScalar fOuterRadius;
27 SkScalar fInnerRadius; 30 SkScalar fInnerRadius;
28 }; 31 };
29 32
30 struct EllipseVertex { 33 struct EllipseVertex {
31 GrPoint fPos; 34 GrPoint fPos;
32 SkScalar fOuterXRadius; 35 SkScalar fOuterXRadius;
33 SkScalar fInnerXRadius; 36 SkScalar fInnerXRadius;
34 GrPoint fOuterOffset; 37 GrPoint fOuterOffset;
35 GrPoint fInnerOffset; 38 GrPoint fInnerOffset;
36 }; 39 };
37 40
41 struct RRectVertex {
42 GrPoint fPos;
43 GrPoint fOffset;
44 GrPoint fOuterRadii;
45 GrPoint fInnerRadii;
46 };
47
38 inline bool circle_stays_circle(const SkMatrix& m) { 48 inline bool circle_stays_circle(const SkMatrix& m) {
39 return m.isSimilarity(); 49 return m.isSimilarity();
40 } 50 }
41 51
42 } 52 }
43 53
44 /////////////////////////////////////////////////////////////////////////////// 54 ///////////////////////////////////////////////////////////////////////////////
45 55
46 /** 56 /**
47 * The output of this effect is a modulation of the input color and coverage for a circle, 57 * The output of this effect is a modulation of the input color and coverage for a circle,
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 278
269 GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random, 279 GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random,
270 GrContext* context, 280 GrContext* context,
271 const GrDrawTargetCaps&, 281 const GrDrawTargetCaps&,
272 GrTexture* textures[]) { 282 GrTexture* textures[]) {
273 return EllipseEdgeEffect::Create(random->nextBool()); 283 return EllipseEdgeEffect::Create(random->nextBool());
274 } 284 }
275 285
276 /////////////////////////////////////////////////////////////////////////////// 286 ///////////////////////////////////////////////////////////////////////////////
277 287
288 /**
289 * The output of this effect is a modulation of the input color and coverage for an axis-aligned
290 * ellipse, specified as an offset vector from center and outer and inner radii in both
291 * x and y directions.
292 *
293 * This uses a slightly different algorithm than the EllipseEdgeEffect, above. R ather than
294 * scaling an ellipse to be a circle, it attempts to find the distance from the offset point to the
295 * ellipse by determining where the line through the origin and offset point wou ld cross the
296 * ellipse, and computing the distance to that. This is slower but works better for roundrects
297 * because the straight edges will be more accurate.
298 */
299
300 class AltEllipseEdgeEffect : public GrEffect {
301 public:
302 static GrEffectRef* Create(bool stroke) {
303 // we go through this so we only have one copy of each effect (stroked/f illed)
304 GR_CREATE_STATIC_EFFECT(gAltEllipseStrokeEdge, AltEllipseEdgeEffect, (tr ue));
305 GR_CREATE_STATIC_EFFECT(gAltEllipseFillEdge, AltEllipseEdgeEffect, (fals e));
306
307 if (stroke) {
308 gAltEllipseStrokeEdge->ref();
309 return gAltEllipseStrokeEdge;
310 } else {
311 gAltEllipseFillEdge->ref();
312 return gAltEllipseFillEdge;
313 }
314 }
315
316 virtual void getConstantColorComponents(GrColor* color,
317 uint32_t* validFlags) const SK_OVERR IDE {
318 *validFlags = 0;
319 }
320
321 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
322 return GrTBackendEffectFactory<AltEllipseEdgeEffect>::getInstance();
323 }
324
325 virtual ~AltEllipseEdgeEffect() {}
326
327 static const char* Name() { return "RRectEdge"; }
328
329 inline bool isStroked() const { return fStroke; }
330
331 class GLEffect : public GrGLEffect {
332 public:
333 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
334 : INHERITED (factory) {}
335
336 virtual void emitCode(GrGLShaderBuilder* builder,
337 const GrDrawEffect& drawEffect,
338 EffectKey key,
339 const char* outputColor,
340 const char* inputColor,
341 const TextureSamplerArray& samplers) SK_OVERRIDE {
342 const AltEllipseEdgeEffect& rrectEffect = drawEffect.castEffect<AltE llipseEdgeEffect>();
343
344 const char *vsOffsetName, *fsOffsetName;
345 const char *vsRadiiName, *fsRadiiName;
346
347 builder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName , &fsOffsetName);
348 const SkString* attr0Name =
349 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]);
350 builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name->c_st r());
351
352 builder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, & fsRadiiName);
353 const SkString* attr1Name =
354 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[1]);
355 builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr1Name->c_str ());
356
357 builder->fsCodeAppend("\tfloat edgeAlpha;\n");
358 // get length of offset
359 builder->fsCodeAppendf("\tfloat len = length(%s.xy);\n", fsOffsetNam e);
360 builder->fsCodeAppend("\tvec2 offset;\n");
361
362 // for outer curve
363 builder->fsCodeAppendf("\toffset.xy = %s.xy*%s.yx;\n",
364 fsOffsetName, fsRadiiName);
365 builder->fsCodeAppendf("\tfloat tOuter = "
366 "%s.x*%s.y*inversesqrt(dot(offset.xy, offset. xy));\n",
367 fsRadiiName, fsRadiiName);
368 builder->fsCodeAppend("\tedgeAlpha = clamp(len*tOuter - len, 0.0, 1. 0);\n");
369
370 // for inner curve
371 if (rrectEffect.isStroked()) {
372 builder->fsCodeAppendf("\toffset.xy = %s.xy*%s.wz;\n",
373 fsOffsetName, fsRadiiName);
374 builder->fsCodeAppendf("\tfloat tInner = "
375 "%s.z*%s.w*inversesqrt(dot(offset.xy, off set.xy));\n",
376 fsRadiiName, fsRadiiName);
377 builder->fsCodeAppend("\tedgeAlpha *= clamp(len - len*tInner, 0. 0, 1.0);\n");
378 }
379
380 SkString modulate;
381 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
382 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() );
383 }
384
385 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) {
386 const AltEllipseEdgeEffect& rrectEffect = drawEffect.castEffect<AltE llipseEdgeEffect>();
387
388 return rrectEffect.isStroked() ? 0x1 : 0x0;
389 }
390
391 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_ OVERRIDE {
392 }
393
394 private:
395 typedef GrGLEffect INHERITED;
396 };
397
398 private:
399 AltEllipseEdgeEffect(bool stroke) : GrEffect() {
400 this->addVertexAttrib(kVec2f_GrSLType);
401 this->addVertexAttrib(kVec4f_GrSLType);
402 fStroke = stroke;
403 }
404
405 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
406 const AltEllipseEdgeEffect& aeee = CastEffect<AltEllipseEdgeEffect>(othe r);
407 return aeee.fStroke == fStroke;
408 }
409
410 bool fStroke;
411
412 GR_DECLARE_EFFECT_TEST;
413
414 typedef GrEffect INHERITED;
415 };
416
417 GR_DEFINE_EFFECT_TEST(AltEllipseEdgeEffect);
418
419 GrEffectRef* AltEllipseEdgeEffect::TestCreate(SkMWCRandom* random,
420 GrContext* context,
421 const GrDrawTargetCaps&,
422 GrTexture* textures[]) {
423 return AltEllipseEdgeEffect::Create(random->nextBool());
424 }
425
426 ///////////////////////////////////////////////////////////////////////////////
427
278 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, co nst GrPaint& paint, 428 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, co nst GrPaint& paint,
279 const GrRect& oval, const SkStrokeRec& stroke) 429 const GrRect& oval, const SkStrokeRec& stroke)
280 { 430 {
281 if (!paint.isAntiAlias()) { 431 if (!paint.isAntiAlias()) {
282 return false; 432 return false;
283 } 433 }
284 434
285 const SkMatrix& vm = context->getMatrix(); 435 const SkMatrix& vm = context->getMatrix();
286 436
287 // we can draw circles 437 // we can draw circles
288 if (SkScalarNearlyEqual(oval.width(), oval.height()) 438 if (SkScalarNearlyEqual(oval.width(), oval.height())
289 && circle_stays_circle(vm)) { 439 && circle_stays_circle(vm)) {
290 drawCircle(target, paint, oval, stroke); 440 drawCircle(target, paint, oval, stroke);
291 441
292 // and axis-aligned ellipses only 442 // and axis-aligned ellipses only
293 } else if (vm.rectStaysRect()) { 443 } else if (vm.rectStaysRect()) {
294 return drawEllipse(target, paint, oval, stroke); 444 return drawEllipse(target, paint, oval, stroke);
295 445
296 } else { 446 } else {
297 return false; 447 return false;
298 } 448 }
299 449
300 return true; 450 return true;
301 } 451 }
302 452
303 namespace { 453 namespace {
304 454
455 ///////////////////////////////////////////////////////////////////////////////
456
305 // position + edge 457 // position + edge
306 extern const GrVertexAttrib gCircleVertexAttribs[] = { 458 extern const GrVertexAttrib gCircleVertexAttribs[] = {
307 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding }, 459 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
308 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding} 460 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
309 }; 461 };
310 462
311 }; 463 };
312 464
313 void GrOvalRenderer::drawCircle(GrDrawTarget* target, 465 void GrOvalRenderer::drawCircle(GrDrawTarget* target,
314 const GrPaint& paint, 466 const GrPaint& paint,
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 verts[2].fInnerRadius = innerRadius; 550 verts[2].fInnerRadius = innerRadius;
399 551
400 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); 552 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
401 verts[3].fOffset = SkPoint::Make(outerRadius, outerRadius); 553 verts[3].fOffset = SkPoint::Make(outerRadius, outerRadius);
402 verts[3].fOuterRadius = outerRadius; 554 verts[3].fOuterRadius = outerRadius;
403 verts[3].fInnerRadius = innerRadius; 555 verts[3].fInnerRadius = innerRadius;
404 556
405 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); 557 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
406 } 558 }
407 559
560 ///////////////////////////////////////////////////////////////////////////////
561
408 namespace { 562 namespace {
409 563
410 // position + edge 564 // position + edge
411 extern const GrVertexAttrib gEllipseVertexAttribs[] = { 565 extern const GrVertexAttrib gEllipseVertexAttribs[] = {
412 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBindi ng}, 566 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBindi ng},
413 {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding }, 567 {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
414 {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint), kEffect_GrVertexAttribBinding } 568 {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
415 }; 569 };
416 570
417 }; 571 };
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked); 632 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked);
479 static const int kEllipseCenterAttrIndex = 1; 633 static const int kEllipseCenterAttrIndex = 1;
480 static const int kEllipseEdgeAttrIndex = 2; 634 static const int kEllipseEdgeAttrIndex = 2;
481 drawState->setEffect(kEdgeEffectStage, effect, 635 drawState->setEffect(kEdgeEffectStage, effect,
482 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref( ); 636 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref( );
483 637
484 SkScalar innerXRadius = 0.0f; 638 SkScalar innerXRadius = 0.0f;
485 SkScalar innerRatio = 1.0f; 639 SkScalar innerRatio = 1.0f;
486 640
487 if (SkStrokeRec::kFill_Style != style) { 641 if (SkStrokeRec::kFill_Style != style) {
488
489
490 if (SkScalarNearlyZero(scaledStroke.length())) { 642 if (SkScalarNearlyZero(scaledStroke.length())) {
491 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); 643 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
492 } else { 644 } else {
493 scaledStroke.scale(0.5f); 645 scaledStroke.scale(0.5f);
494 } 646 }
495 647
496 // this is legit only if scale & translation (which should be the case a t the moment) 648 // this is legit only if scale & translation (which should be the case a t the moment)
497 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) { 649 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) {
498 SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); 650 SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY);
499 if (innerYRadius > SK_ScalarNearlyZero) { 651 if (innerYRadius > SK_ScalarNearlyZero) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
545 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); 697 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
546 verts[3].fOuterXRadius = xRadius; 698 verts[3].fOuterXRadius = xRadius;
547 verts[3].fInnerXRadius = innerXRadius; 699 verts[3].fInnerXRadius = innerXRadius;
548 verts[3].fOuterOffset = SkPoint::Make(xRadius, outerRatio*yRadius); 700 verts[3].fOuterOffset = SkPoint::Make(xRadius, outerRatio*yRadius);
549 verts[3].fInnerOffset = SkPoint::Make(xRadius, innerRatio*yRadius); 701 verts[3].fInnerOffset = SkPoint::Make(xRadius, innerRatio*yRadius);
550 702
551 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); 703 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
552 704
553 return true; 705 return true;
554 } 706 }
707
708 ///////////////////////////////////////////////////////////////////////////////
709
710 static const uint16_t gRRectIndices[] = {
711 // corners
712 0, 1, 5, 0, 5, 4,
713 2, 3, 7, 2, 7, 6,
714 8, 9, 13, 8, 13, 12,
715 10, 11, 15, 10, 15, 14,
716
717 // edges
718 1, 2, 6, 1, 6, 5,
719 4, 5, 9, 4, 9, 8,
720 6, 7, 11, 6, 11, 10,
721 9, 10, 14, 9, 14, 13,
722
723 // center
724 // we place this at the end so that we can ignore these indices when renderi ng stroke-only
725 5, 6, 10, 5, 10, 9
726 };
727
728
729 GrIndexBuffer* GrOvalRenderer::rRectIndexBuffer(GrGpu* gpu) {
730 if (NULL == fRRectIndexBuffer) {
731 fRRectIndexBuffer =
732 gpu->createIndexBuffer(sizeof(gRRectIndices), false);
733 if (NULL != fRRectIndexBuffer) {
734 #if GR_DEBUG
735 bool updated =
736 #endif
737 fRRectIndexBuffer->updateData(gRRectIndices,
738 sizeof(gRRectIndices));
739 GR_DEBUGASSERT(updated);
740 }
741 }
742 return fRRectIndexBuffer;
743 }
744
745 bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, GrContext* context,
746 const GrPaint& paint, const SkRRect& rrect,
747 const SkStrokeRec& stroke)
748 {
749 const SkMatrix& vm = context->getMatrix();
750 #ifdef SK_DEBUG
751 {
752 // we should have checked for this previously
753 SkASSERT(paint.isAntiAlias() && vm.rectStaysRect() && rrect.isSimple());
754 }
755 #endif
756
757 // do any matrix crunching before we reset the draw state for device coords
758 const SkRect& rrectBounds = rrect.getBounds();
759 SkRect bounds;
760 vm.mapRect(&bounds, rrectBounds);
761
762 SkVector radii = rrect.getSimpleRadii();
763 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX +
764 vm[SkMatrix::kMSkewY]*radii.fY);
765 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX +
766 vm[SkMatrix::kMScaleY]*radii.fY);
767 // tall or wide quarter-ellipse corners aren't handled
768 if (SkScalarDiv(xRadius, yRadius) > 2 || SkScalarDiv(yRadius, xRadius) > 2) {
769 return false;
770 }
771 // if hairline stroke is greater than radius, we don't handle that right now
772 SkStrokeRec::Style style = stroke.getStyle();
773 if (SkStrokeRec::kHairline_Style == style &&
774 (SK_ScalarHalf >= xRadius || SK_ScalarHalf >= yRadius)) {
775 return false;
776 }
777
778 // do (potentially) anisotropic mapping of stroke
779 SkVector scaledStroke;
780 SkScalar strokeWidth = stroke.getWidth();
781 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat rix::kMSkewY]));
782 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr ix::kMScaleY]));
783
784 // if half of strokewidth is greater than radius, we don't handle that right now
785 if (SK_ScalarHalf*scaledStroke.fX >= xRadius || SK_ScalarHalf*scaledStroke.f Y >= yRadius) {
786 return false;
787 }
788
789 // reset to device coordinates
790 GrDrawState* drawState = target->drawState();
791 GrDrawState::AutoDeviceCoordDraw adcd(drawState);
792 if (!adcd.succeeded()) {
793 return false;
794 }
795
796 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style);
797
798 enum {
799 // the edge effects share this stage with glyph rendering
800 // (kGlyphMaskStage in GrTextContext) && SW path rendering
801 // (kPathMaskStage in GrSWMaskHelper)
802 kEdgeEffectStage = GrPaint::kTotalStages,
803 };
804
805 GrIndexBuffer* indexBuffer = this->rRectIndexBuffer(context->getGpu());
806 if (NULL == indexBuffer) {
807 GrPrintf("Failed to create index buffer!\n");
808 return false;
809 }
810
811 // if the corners are circles, use the circle renderer
812 if ((!isStroked || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius ) {
813 drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircle VertexAttribs));
814 GrAssert(sizeof(CircleVertex) == drawState->getVertexSize());
815
816 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
817 if (!geo.succeeded()) {
818 GrPrintf("Failed to get space for vertices!\n");
819 return false;
820 }
821 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
822
823 GrEffectRef* effect = CircleEdgeEffect::Create(isStroked);
824 static const int kCircleEdgeAttrIndex = 1;
825 drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->un ref();
826
827 SkScalar innerRadius = 0.0f;
828 SkScalar outerRadius = xRadius;
829 SkScalar halfWidth = 0;
830 if (style != SkStrokeRec::kFill_Style) {
831 if (SkScalarNearlyZero(scaledStroke.fX)) {
832 halfWidth = SK_ScalarHalf;
833 } else {
834 halfWidth = SkScalarHalf(scaledStroke.fX);
835 }
836
837 if (isStroked) {
838 innerRadius = SkMaxScalar(0, xRadius - halfWidth);
839 }
840 outerRadius += halfWidth;
841 bounds.outset(halfWidth, halfWidth);
842 }
843
844 // The radii are outset for two reasons. First, it allows the shader to simply perform
845 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the
846 // verts of the bounding box that is rendered and the outset ensures the box will cover all
847 // pixels partially covered by the circle.
848 outerRadius += SK_ScalarHalf;
849 innerRadius -= SK_ScalarHalf;
850
851 // Expand the rect so all the pixels will be captured.
852 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
853
854 SkScalar yCoords[4] = {
855 bounds.fTop,
856 bounds.fTop + outerRadius,
857 bounds.fBottom - outerRadius,
858 bounds.fBottom
859 };
860 SkScalar yOuterRadii[4] = {
861 -outerRadius,
862 0,
863 0,
864 outerRadius
865 };
866 for (int i = 0; i < 4; ++i) {
867 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
868 verts->fOffset = SkPoint::Make(-outerRadius, yOuterRadii[i]);
869 verts->fOuterRadius = outerRadius;
870 verts->fInnerRadius = innerRadius;
871 verts++;
872
873 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
874 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
875 verts->fOuterRadius = outerRadius;
876 verts->fInnerRadius = innerRadius;
877 verts++;
878
879 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]) ;
880 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
881 verts->fOuterRadius = outerRadius;
882 verts->fInnerRadius = innerRadius;
883 verts++;
884
885 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
886 verts->fOffset = SkPoint::Make(outerRadius, yOuterRadii[i]);
887 verts->fOuterRadius = outerRadius;
888 verts->fInnerRadius = innerRadius;
889 verts++;
890 }
891
892 // drop out the middle quad if we're stroked
893 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO UNT(gRRectIndices);
894 target->setIndexSourceToBuffer(indexBuffer);
895 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds);
896
897 // otherwise we use the special ellipse renderer
898 } else {
899
900 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllip seVertexAttribs));
901 GrAssert(sizeof(RRectVertex) == drawState->getVertexSize());
902
903 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
904 if (!geo.succeeded()) {
905 GrPrintf("Failed to get space for vertices!\n");
906 return false;
907 }
908 RRectVertex* verts = reinterpret_cast<RRectVertex*>(geo.vertices());
909
910 GrEffectRef* effect = AltEllipseEdgeEffect::Create(isStroked);
911 static const int kEllipseOffsetAttrIndex = 1;
912 static const int kEllipseRadiiAttrIndex = 2;
913 drawState->setEffect(kEdgeEffectStage, effect,
914 kEllipseOffsetAttrIndex, kEllipseRadiiAttrIndex)->u nref();
915
916 SkScalar innerXRadius = 0.0f;
917 SkScalar innerYRadius = 0.0f;
918
919 if (SkStrokeRec::kFill_Style != style) {
920 if (SkScalarNearlyZero(scaledStroke.length())) {
921 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
922 } else {
923 scaledStroke.scale(0.5f);
924 }
925
926 // this is legit only if scale & translation (which should be the ca se at the moment)
927 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_St yle == style) {
928 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX);
929 innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY);
930 }
931 xRadius += scaledStroke.fX;
932 yRadius += scaledStroke.fY;
933 bounds.outset(scaledStroke.fX, scaledStroke.fY);
934 }
935
936 // Extend the radii out half a pixel to antialias.
937 SkScalar xOuterRadius = xRadius + SK_ScalarHalf;
938 SkScalar yOuterRadius = yRadius + SK_ScalarHalf;
939 SkScalar xInnerRadius = SkMaxScalar(innerXRadius - SK_ScalarHalf, 0);
940 SkScalar yInnerRadius = SkMaxScalar(innerYRadius - SK_ScalarHalf, 0);
941
942 // Expand the rect so all the pixels will be captured.
943 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
944
945 SkScalar yCoords[4] = {
946 bounds.fTop,
947 bounds.fTop + yOuterRadius,
948 bounds.fBottom - yOuterRadius,
949 bounds.fBottom
950 };
951 SkScalar yOuterOffsets[4] = {
952 -yOuterRadius,
953 SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so can't be exactly 0
954 SK_ScalarNearlyZero,
955 yOuterRadius
956 };
957
958 for (int i = 0; i < 4; ++i) {
959 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
960 verts->fOffset = SkPoint::Make(-xOuterRadius, yOuterOffsets[i]);
961 verts->fOuterRadii = SkPoint::Make(xOuterRadius, yOuterRadius);
962 verts->fInnerRadii = SkPoint::Make(xInnerRadius, yInnerRadius);
963 verts++;
964
965 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]) ;
966 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] );
967 verts->fOuterRadii = SkPoint::Make(xOuterRadius, yOuterRadius);
968 verts->fInnerRadii = SkPoint::Make(xInnerRadius, yInnerRadius);
969 verts++;
970
971 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i] );
972 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] );
973 verts->fOuterRadii = SkPoint::Make(xOuterRadius, yOuterRadius);
974 verts->fInnerRadii = SkPoint::Make(xInnerRadius, yInnerRadius);
975 verts++;
976
977 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
978 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]);
979 verts->fOuterRadii = SkPoint::Make(xOuterRadius, yOuterRadius);
980 verts->fInnerRadii = SkPoint::Make(xInnerRadius, yInnerRadius);
981 verts++;
982 }
983
984 // drop out the middle quad if we're stroked
985 int indexCnt = isStroked ? GR_ARRAY_COUNT(gRRectIndices)-6 : GR_ARRAY_CO UNT(gRRectIndices);
986 target->setIndexSourceToBuffer(indexBuffer);
987 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds);
988 }
989
990 return true;
991 }
992
OLDNEW
« no previous file with comments | « src/gpu/GrContext.cpp ('k') | src/gpu/SkGpuDevice.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698