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

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

Powered by Google App Engine
This is Rietveld 408576698