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

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

Issue 2272703004: Add Ganesh support for circular roundrects with strokes > 2*radii. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Degenerate to fill for superwide strokes Created 4 years, 3 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
« no previous file with comments | « no previous file | no next file » | 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 "GrBatchFlushState.h" 10 #include "GrBatchFlushState.h"
(...skipping 1317 matching lines...) Expand 10 before | Expand all | Expand 10 after
1328 }; 1328 };
1329 1329
1330 bool fUsesLocalCoords; 1330 bool fUsesLocalCoords;
1331 SkSTArray<1, Geometry, true> fGeoData; 1331 SkSTArray<1, Geometry, true> fGeoData;
1332 1332
1333 typedef GrVertexBatch INHERITED; 1333 typedef GrVertexBatch INHERITED;
1334 }; 1334 };
1335 1335
1336 /////////////////////////////////////////////////////////////////////////////// 1336 ///////////////////////////////////////////////////////////////////////////////
1337 1337
1338 static const uint16_t gRRectIndices[] = { 1338 // We have three possible cases for geometry for a roundrect.
1339 //
1340 // In the case of a normal fill or a stroke, we draw the roundrect as a 9-patch:
1341 // ____________
1342 // |_|________|_|
1343 // | | | |
1344 // | | | |
1345 // | | | |
1346 // |_|________|_|
1347 // |_|________|_|
1348 //
1349 // For strokes, we don't draw the center quad.
1350 //
1351 // For circular roundrects, in the case where the stroke width is greater than t wice
1352 // the corner radius (overstroke), we add additional geometry to mark out the re ctangle
1353 // in the center:
1354 // ____________
1355 // |_|________|_|
1356 // | |\ ____ /| |
1357 // | | | | | |
1358 // | | |____| | |
1359 // |_|/______\|_|
1360 // |_|________|_|
1361 //
1362 // We don't draw the center quad from the fill rect in this case.
1363
1364 static const uint16_t gRRectOverstrokeIndices[] = {
1365 // overstroke quads
1366 // we place this at the beginning so that we can skip these indices when ren dering normally
1367 5, 6, 17, 5, 17, 16,
1368 17, 6, 10, 17, 10, 19,
1369 10, 9, 18, 10, 18, 19,
1370 18, 9, 5, 18, 5, 16,
1371
1339 // corners 1372 // corners
1340 0, 1, 5, 0, 5, 4, 1373 0, 1, 5, 0, 5, 4,
1341 2, 3, 7, 2, 7, 6, 1374 2, 3, 7, 2, 7, 6,
1342 8, 9, 13, 8, 13, 12, 1375 8, 9, 13, 8, 13, 12,
1343 10, 11, 15, 10, 15, 14, 1376 10, 11, 15, 10, 15, 14,
1344 1377
1345 // edges 1378 // edges
1346 1, 2, 6, 1, 6, 5, 1379 1, 2, 6, 1, 6, 5,
1347 4, 5, 9, 4, 9, 8, 1380 4, 5, 9, 4, 9, 8,
1348 6, 7, 11, 6, 11, 10, 1381 6, 7, 11, 6, 11, 10,
1349 9, 10, 14, 9, 14, 13, 1382 9, 10, 14, 9, 14, 13,
1350 1383
1351 // center 1384 // center
1352 // we place this at the end so that we can ignore these indices when renderi ng stroke-only 1385 // we place this at the end so that we can ignore these indices when not ren dering as filled
1353 5, 6, 10, 5, 10, 9 1386 5, 6, 10, 5, 10, 9,
1354 }; 1387 };
1355 1388
1356 static const int kIndicesPerStrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6; 1389 static const uint16_t* gRRectIndices = gRRectOverstrokeIndices + 6*4;
1357 static const int kIndicesPerRRect = SK_ARRAY_COUNT(gRRectIndices); 1390
1358 static const int kVertsPerRRect = 16; 1391 // overstroke count is arraysize
1392 static const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gRRectOverstrokeInd ices) - 6;
1393 static const int kIndicesPerFillRRect = kIndicesPerOverstrokeRRect - 6*4 + 6;
1394 static const int kIndicesPerStrokeRRect = kIndicesPerFillRRect - 6;
1395 static const int kVertsPerStandardRRect = 16;
1396 static const int kVertsPerOverstrokeRRect = 20;
1359 static const int kNumRRectsInIndexBuffer = 256; 1397 static const int kNumRRectsInIndexBuffer = 256;
1360 1398
1399 enum RRectType {
1400 kFill_RRectType,
1401 kStroke_RRectType,
1402 kOverstroke_RRectType
1403 };
1404
1361 GR_DECLARE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey); 1405 GR_DECLARE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
1362 GR_DECLARE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey); 1406 GR_DECLARE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
1363 static const GrBuffer* ref_rrect_index_buffer(bool strokeOnly, 1407 GR_DECLARE_STATIC_UNIQUE_KEY(gOverstrokeRRectOnlyIndexBufferKey);
1408 static const GrBuffer* ref_rrect_index_buffer(RRectType type,
1364 GrResourceProvider* resourceProvid er) { 1409 GrResourceProvider* resourceProvid er) {
1365 GR_DEFINE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey); 1410 GR_DEFINE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
1366 GR_DEFINE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey); 1411 GR_DEFINE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
1367 if (strokeOnly) { 1412 GR_DEFINE_STATIC_UNIQUE_KEY(gOverstrokeRRectOnlyIndexBufferKey);
1368 return resourceProvider->findOrCreateInstancedIndexBuffer( 1413 switch (type) {
1369 gRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer, kVer tsPerRRect, 1414 case kFill_RRectType:
1370 gStrokeRRectOnlyIndexBufferKey); 1415 default:
1371 } else { 1416 return resourceProvider->findOrCreateInstancedIndexBuffer(
1372 return resourceProvider->findOrCreateInstancedIndexBuffer( 1417 gRRectIndices, kIndicesPerFillRRect, kNumRRectsInIndexBuffer,
1373 gRRectIndices, kIndicesPerRRect, kNumRRectsInIndexBuffer, kVertsPerR Rect, 1418 kVertsPerStandardRRect, gRRectOnlyIndexBufferKey);
1374 gRRectOnlyIndexBufferKey); 1419 case kStroke_RRectType:
1375 1420 return resourceProvider->findOrCreateInstancedIndexBuffer(
1376 } 1421 gRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer,
1422 kVertsPerStandardRRect, gStrokeRRectOnlyIndexBufferKey);
1423 case kOverstroke_RRectType:
1424 return resourceProvider->findOrCreateInstancedIndexBuffer(
1425 gRRectOverstrokeIndices, kIndicesPerOverstrokeRRect, kNumRRectsI nIndexBuffer,
1426 kVertsPerOverstrokeRRect, gOverstrokeRRectOnlyIndexBufferKey);
1427 };
1377 } 1428 }
1378 1429
1379 //////////////////////////////////////////////////////////////////////////////// /////////////////// 1430 //////////////////////////////////////////////////////////////////////////////// ///////////////////
1380 1431
1381 class RRectCircleRendererBatch : public GrVertexBatch { 1432 class RRectCircleRendererBatch : public GrVertexBatch {
1382 public: 1433 public:
1383 DEFINE_BATCH_CLASS_ID 1434 DEFINE_BATCH_CLASS_ID
1384 1435
1385 // A devStrokeWidth <= 0 indicates a fill only. If devStrokeWidth > 0 then s trokeOnly indicates 1436 // A devStrokeWidth <= 0 indicates a fill only. If devStrokeWidth > 0 then s trokeOnly indicates
1386 // whether the rrect is only stroked or stroked and filled. 1437 // whether the rrect is only stroked or stroked and filled.
1387 RRectCircleRendererBatch(GrColor color, const SkMatrix& viewMatrix, const Sk Rect& devRect, 1438 RRectCircleRendererBatch(GrColor color, const SkMatrix& viewMatrix, const Sk Rect& devRect,
1388 float devRadius, float devStrokeWidth, bool strokeO nly) 1439 float devRadius, float devStrokeWidth, bool strokeO nly)
1389 : INHERITED(ClassID()) 1440 : INHERITED(ClassID())
1390 , fViewMatrixIfUsingLocalCoords(viewMatrix) { 1441 , fViewMatrixIfUsingLocalCoords(viewMatrix) {
1391 SkRect bounds = devRect; 1442 SkRect bounds = devRect;
1392 SkASSERT(!(devStrokeWidth <= 0 && strokeOnly)); 1443 SkASSERT(!(devStrokeWidth <= 0 && strokeOnly));
1393 SkScalar innerRadius = 0.0f; 1444 SkScalar innerRadius = 0.0f;
1394 SkScalar outerRadius = devRadius; 1445 SkScalar outerRadius = devRadius;
1395 SkScalar halfWidth = 0; 1446 SkScalar halfWidth = 0;
1396 fStroked = false; 1447 fType = kFill_RRectType;
1397 if (devStrokeWidth > 0) { 1448 if (devStrokeWidth > 0) {
1398 if (SkScalarNearlyZero(devStrokeWidth)) { 1449 if (SkScalarNearlyZero(devStrokeWidth)) {
1399 halfWidth = SK_ScalarHalf; 1450 halfWidth = SK_ScalarHalf;
1400 } else { 1451 } else {
1401 halfWidth = SkScalarHalf(devStrokeWidth); 1452 halfWidth = SkScalarHalf(devStrokeWidth);
1402 } 1453 }
1403 1454
1404 if (strokeOnly) { 1455 if (strokeOnly) {
1405 innerRadius = devRadius - halfWidth; 1456 // Outset stroke by 1/4 pixel
1406 fStroked = innerRadius >= 0; 1457 devStrokeWidth += 0.25f;
1458 // If stroke is greater than width or height, this is still a fi ll
1459 // Otherwise we compute stroke params
1460 if (devStrokeWidth <= devRect.width() &&
1461 devStrokeWidth <= devRect.height()) {
1462 innerRadius = devRadius - halfWidth;
1463 fType = (innerRadius >= 0) ? kStroke_RRectType : kOverstroke _RRectType;
1464 }
1407 } 1465 }
1408 outerRadius += halfWidth; 1466 outerRadius += halfWidth;
1409 bounds.outset(halfWidth, halfWidth); 1467 bounds.outset(halfWidth, halfWidth);
1410 } 1468 }
1411 1469
1412 // The radii are outset for two reasons. First, it allows the shader to simply perform 1470 // The radii are outset for two reasons. First, it allows the shader to simply perform
1413 // simpler computation because the computed alpha is zero, rather than 5 0%, at the radius. 1471 // simpler computation because the computed alpha is zero, rather than 5 0%, at the radius.
1414 // Second, the outer radius is used to compute the verts of the bounding box that is 1472 // Second, the outer radius is used to compute the verts of the bounding box that is
1415 // rendered and the outset ensures the box will cover all partially cove red by the rrect 1473 // rendered and the outset ensures the box will cover all partially cove red by the rrect
1416 // corners. 1474 // corners.
1417 outerRadius += SK_ScalarHalf; 1475 outerRadius += SK_ScalarHalf;
1418 innerRadius -= SK_ScalarHalf; 1476 innerRadius -= SK_ScalarHalf;
1419 1477
1420 this->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo); 1478 this->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo);
1421 1479
1422 // Expand the rect for aa to generate correct vertices. 1480 // Expand the rect for aa to generate correct vertices.
1423 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); 1481 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1424 1482
1425 fGeoData.emplace_back(Geometry { color, innerRadius, outerRadius, bounds }); 1483 fGeoData.emplace_back(Geometry { color, innerRadius, outerRadius, bounds });
1426 } 1484 }
1427 1485
1428 const char* name() const override { return "RRectCircleBatch"; } 1486 const char* name() const override { return "RRectCircleBatch"; }
1429 1487
1488 SkString dumpInfo() const override {
1489 SkString string;
1490 for (int i = 0; i < fGeoData.count(); ++i) {
1491 string.appendf("Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %. 2f],"
1492 "InnerRad: %.2f, OuterRad: %.2f\n",
1493 fGeoData[i].fColor,
1494 fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds. fTop,
1495 fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds .fBottom,
1496 fGeoData[i].fInnerRadius,
1497 fGeoData[i].fOuterRadius);
1498 }
1499 string.append(INHERITED::dumpInfo());
1500 return string;
1501 }
1502
1430 void computePipelineOptimizations(GrInitInvariantOutput* color, 1503 void computePipelineOptimizations(GrInitInvariantOutput* color,
1431 GrInitInvariantOutput* coverage, 1504 GrInitInvariantOutput* coverage,
1432 GrBatchToXPOverrides* overrides) const ove rride { 1505 GrBatchToXPOverrides* overrides) const ove rride {
1433 // When this is called on a batch, there is only one geometry bundle 1506 // When this is called on a batch, there is only one geometry bundle
1434 color->setKnownFourComponents(fGeoData[0].fColor); 1507 color->setKnownFourComponents(fGeoData[0].fColor);
1435 coverage->setUnknownSingleComponent(); 1508 coverage->setUnknownSingleComponent();
1436 } 1509 }
1437 1510
1438 private: 1511 private:
1439 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { 1512 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
1440 // Handle any overrides that affect our GP. 1513 // Handle any overrides that affect our GP.
1441 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); 1514 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
1442 if (!overrides.readsLocalCoords()) { 1515 if (!overrides.readsLocalCoords()) {
1443 fViewMatrixIfUsingLocalCoords.reset(); 1516 fViewMatrixIfUsingLocalCoords.reset();
1444 } 1517 }
1445 } 1518 }
1446 1519
1447 void onPrepareDraws(Target* target) const override { 1520 void onPrepareDraws(Target* target) const override {
1448 // Invert the view matrix as a local matrix (if any other processors req uire coords). 1521 // Invert the view matrix as a local matrix (if any other processors req uire coords).
1449 SkMatrix localMatrix; 1522 SkMatrix localMatrix;
1450 if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) { 1523 if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) {
1451 return; 1524 return;
1452 } 1525 }
1453 1526
1454 // Setup geometry processor 1527 // Setup geometry processor
1455 SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(fStroke d, false, false, 1528 SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(kStroke _RRectType == fType,
1529 false, false,
1456 false, localMatrix)); 1530 false, localMatrix));
1457 1531
1458 struct CircleVertex { 1532 struct CircleVertex {
1459 SkPoint fPos; 1533 SkPoint fPos;
1460 GrColor fColor; 1534 GrColor fColor;
1461 SkPoint fOffset; 1535 SkPoint fOffset;
1462 SkScalar fOuterRadius; 1536 SkScalar fOuterRadius;
1463 SkScalar fInnerRadius; 1537 SkScalar fInnerRadius;
1464 // No half plane, we don't use it here. 1538 // No half plane, we don't use it here.
1465 }; 1539 };
1466 1540
1467 int instanceCount = fGeoData.count(); 1541 int instanceCount = fGeoData.count();
1468 size_t vertexStride = gp->getVertexStride(); 1542 size_t vertexStride = gp->getVertexStride();
1469 SkASSERT(vertexStride == sizeof(CircleVertex)); 1543 SkASSERT(vertexStride == sizeof(CircleVertex));
1470 1544
1471 // drop out the middle quad if we're stroked 1545 // drop out the middle quad if we're stroked
1472 int indicesPerInstance = fStroked ? kIndicesPerStrokeRRect : kIndicesPer RRect; 1546 int indicesPerInstance = kIndicesPerFillRRect;
1547 if (kStroke_RRectType == fType) {
1548 indicesPerInstance = kIndicesPerStrokeRRect;
1549 } else if (kOverstroke_RRectType == fType) {
1550 indicesPerInstance = kIndicesPerOverstrokeRRect;
1551 }
1473 SkAutoTUnref<const GrBuffer> indexBuffer( 1552 SkAutoTUnref<const GrBuffer> indexBuffer(
1474 ref_rrect_index_buffer(fStroked, target->resourceProvider())); 1553 ref_rrect_index_buffer(fType, target->resourceProvider()));
1475 1554
1476 InstancedHelper helper; 1555 InstancedHelper helper;
1556 int vertexCount = (kOverstroke_RRectType == fType) ? kVertsPerOverstroke RRect
1557 : kVertsPerStandardRR ect;
1477 CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target , 1558 CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target ,
1478 kTriangles_GrPrimitiveType, vertexStride, indexBuffer, kVertsPerRRec t, 1559 kTriangles_GrPrimitiveType, vertexStride, indexBuffer, vertexCount,
1479 indicesPerInstance, instanceCount)); 1560 indicesPerInstance, instanceCount));
1480 if (!verts || !indexBuffer) { 1561 if (!verts || !indexBuffer) {
1481 SkDebugf("Could not allocate vertices\n"); 1562 SkDebugf("Could not allocate vertices\n");
1482 return; 1563 return;
1483 } 1564 }
1484 1565
1485 for (int i = 0; i < instanceCount; i++) { 1566 for (int i = 0; i < instanceCount; i++) {
1486 const Geometry& args = fGeoData[i]; 1567 const Geometry& args = fGeoData[i];
1487 1568
1488 GrColor color = args.fColor; 1569 GrColor color = args.fColor;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1522 verts->fInnerRadius = innerRadius; 1603 verts->fInnerRadius = innerRadius;
1523 verts++; 1604 verts++;
1524 1605
1525 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); 1606 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1526 verts->fColor = color; 1607 verts->fColor = color;
1527 verts->fOffset = SkPoint::Make(1, yOuterRadii[i]); 1608 verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
1528 verts->fOuterRadius = outerRadius; 1609 verts->fOuterRadius = outerRadius;
1529 verts->fInnerRadius = innerRadius; 1610 verts->fInnerRadius = innerRadius;
1530 verts++; 1611 verts++;
1531 } 1612 }
1613 // Add the additional vertices for overstroked rrects.
1614 //
1615 // Note that args.fInnerRadius is negative in this case.
1616 // Also, the offset is a constant vector pointing to the right, whic h guarantees
1617 // that the distance value along the inner rectangle is constant, wh ich
1618 // is what we want to get nice anti-aliasing.
1619 if (kOverstroke_RRectType == fType) {
1620 // outerRadius = originalOuter + 0.5, and innerRadius = original Inner - 0.5.
1621 // What we want is originalOuter - originalInner + 0.5, so we su btract 0.5.
1622 SkScalar inset = outerRadius - args.fInnerRadius - SK_ScalarHalf ;
1623 verts->fPos = SkPoint::Make(bounds.fLeft + inset,
1624 bounds.fTop + inset);
1625 verts->fColor = color;
1626 verts->fOffset = SkPoint::Make(1, 0);
1627 verts->fOuterRadius = outerRadius;
1628 verts->fInnerRadius = innerRadius;
1629 verts++;
1630
1631 verts->fPos = SkPoint::Make(bounds.fRight - inset,
1632 bounds.fTop + inset);
1633 verts->fColor = color;
1634 verts->fOffset = SkPoint::Make(1, 0);
1635 verts->fOuterRadius = outerRadius;
1636 verts->fInnerRadius = innerRadius;
1637 verts++;
1638
1639 verts->fPos = SkPoint::Make(bounds.fLeft + inset,
1640 bounds.fBottom - inset);
1641 verts->fColor = color;
1642 verts->fOffset = SkPoint::Make(1, 0);
1643 verts->fOuterRadius = outerRadius;
1644 verts->fInnerRadius = innerRadius;
1645 verts++;
1646
1647 verts->fPos = SkPoint::Make(bounds.fRight - inset,
1648 bounds.fBottom - inset);
1649 verts->fColor = color;
1650 verts->fOffset = SkPoint::Make(1, 0);
1651 verts->fOuterRadius = outerRadius;
1652 verts->fInnerRadius = innerRadius;
1653 verts++;
1654 }
1532 } 1655 }
1533 1656
1534 helper.recordDraw(target, gp); 1657 helper.recordDraw(target, gp);
1535 } 1658 }
1536 1659
1537 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { 1660 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
1538 RRectCircleRendererBatch* that = t->cast<RRectCircleRendererBatch>(); 1661 RRectCircleRendererBatch* that = t->cast<RRectCircleRendererBatch>();
1539 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(), 1662 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(),
1540 that->bounds(), caps)) { 1663 that->bounds(), caps)) {
1541 return false; 1664 return false;
1542 } 1665 }
1543 1666
1544 if (fStroked != that->fStroked) { 1667 if (fType != that->fType) {
1545 return false; 1668 return false;
1546 } 1669 }
1547 1670
1548 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) { 1671 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) {
1549 return false; 1672 return false;
1550 } 1673 }
1551 1674
1552 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); 1675 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
1553 this->joinBounds(*that); 1676 this->joinBounds(*that);
1554 return true; 1677 return true;
1555 } 1678 }
1556 1679
1557 struct Geometry { 1680 struct Geometry {
1558 GrColor fColor; 1681 GrColor fColor;
1559 SkScalar fInnerRadius; 1682 SkScalar fInnerRadius;
1560 SkScalar fOuterRadius; 1683 SkScalar fOuterRadius;
1561 SkRect fDevBounds; 1684 SkRect fDevBounds;
1562 }; 1685 };
1563 1686
1564 bool fStroked; 1687 RRectType fType;
1565 SkMatrix fViewMatrixIfUsingLocalCoords; 1688 SkMatrix fViewMatrixIfUsingLocalCoords;
1566 SkSTArray<1, Geometry, true> fGeoData; 1689 SkSTArray<1, Geometry, true> fGeoData;
1567 1690
1568 typedef GrVertexBatch INHERITED; 1691 typedef GrVertexBatch INHERITED;
1569 }; 1692 };
1570 1693
1571 class RRectEllipseRendererBatch : public GrVertexBatch { 1694 class RRectEllipseRendererBatch : public GrVertexBatch {
1572 public: 1695 public:
1573 DEFINE_BATCH_CLASS_ID 1696 DEFINE_BATCH_CLASS_ID
1574 1697
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1659 } 1782 }
1660 1783
1661 // Setup geometry processor 1784 // Setup geometry processor
1662 SkAutoTUnref<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStrok ed, localMatrix)); 1785 SkAutoTUnref<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStrok ed, localMatrix));
1663 1786
1664 int instanceCount = fGeoData.count(); 1787 int instanceCount = fGeoData.count();
1665 size_t vertexStride = gp->getVertexStride(); 1788 size_t vertexStride = gp->getVertexStride();
1666 SkASSERT(vertexStride == sizeof(EllipseVertex)); 1789 SkASSERT(vertexStride == sizeof(EllipseVertex));
1667 1790
1668 // drop out the middle quad if we're stroked 1791 // drop out the middle quad if we're stroked
1669 int indicesPerInstance = fStroked ? kIndicesPerStrokeRRect : kIndicesPer RRect; 1792 int indicesPerInstance = fStroked ? kIndicesPerStrokeRRect : kIndicesPer FillRRect;
1670 SkAutoTUnref<const GrBuffer> indexBuffer( 1793 SkAutoTUnref<const GrBuffer> indexBuffer(
1671 ref_rrect_index_buffer(fStroked, target->resourceProvider())); 1794 ref_rrect_index_buffer(fStroked ? kStroke_RRectType : kFill_RRectTyp e,
1795 target->resourceProvider()));
1672 1796
1673 InstancedHelper helper; 1797 InstancedHelper helper;
1674 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>( 1798 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
1675 helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexB uffer, 1799 helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexB uffer,
1676 kVertsPerRRect, indicesPerInstance, instanceCount)); 1800 kVertsPerStandardRRect, indicesPerInstance, instanceCoun t));
1677 if (!verts || !indexBuffer) { 1801 if (!verts || !indexBuffer) {
1678 SkDebugf("Could not allocate vertices\n"); 1802 SkDebugf("Could not allocate vertices\n");
1679 return; 1803 return;
1680 } 1804 }
1681 1805
1682 for (int i = 0; i < instanceCount; i++) { 1806 for (int i = 0; i < instanceCount; i++) {
1683 const Geometry& args = fGeoData[i]; 1807 const Geometry& args = fGeoData[i];
1684 1808
1685 GrColor color = args.fColor; 1809 GrColor color = args.fColor;
1686 1810
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
1802 SkStrokeRec::Style style = stroke.getStyle(); 1926 SkStrokeRec::Style style = stroke.getStyle();
1803 1927
1804 // Do (potentially) anisotropic mapping of stroke. Use -1s to indicate fill- only draws. 1928 // Do (potentially) anisotropic mapping of stroke. Use -1s to indicate fill- only draws.
1805 SkVector scaledStroke = {-1, -1}; 1929 SkVector scaledStroke = {-1, -1};
1806 SkScalar strokeWidth = stroke.getWidth(); 1930 SkScalar strokeWidth = stroke.getWidth();
1807 1931
1808 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || 1932 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
1809 SkStrokeRec::kHairline_Style == style; 1933 SkStrokeRec::kHairline_Style == style;
1810 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; 1934 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
1811 1935
1936 bool isCircular = (xRadius == yRadius);
1812 if (hasStroke) { 1937 if (hasStroke) {
1813 if (SkStrokeRec::kHairline_Style == style) { 1938 if (SkStrokeRec::kHairline_Style == style) {
1814 scaledStroke.set(1, 1); 1939 scaledStroke.set(1, 1);
1815 } else { 1940 } else {
1816 scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSc aleX] + 1941 scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSc aleX] +
1817 viewMatrix[SkMatrix::kMSk ewY])); 1942 viewMatrix[SkMatrix::kMSk ewY]));
1818 scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSk ewX] + 1943 scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSk ewX] +
1819 viewMatrix[SkMatrix::kMSc aleY])); 1944 viewMatrix[SkMatrix::kMSc aleY]));
1820 } 1945 }
1821 1946
1822 // if half of strokewidth is greater than radius, we don't handle that r ight now 1947 isCircular = isCircular && scaledStroke.fX == scaledStroke.fY;
1823 if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStrok e.fY > yRadius) { 1948 // for non-circular rrects, if half of strokewidth is greater than radiu s,
1949 // we don't handle that right now
1950 if (!isCircular &&
1951 (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStro ke.fY > yRadius)) {
1824 return nullptr; 1952 return nullptr;
1825 } 1953 }
1826 } 1954 }
1827 1955
1828 // The way the effect interpolates the offset-to-ellipse/circle-center attri bute only works on 1956 // The way the effect interpolates the offset-to-ellipse/circle-center attri bute only works on
1829 // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner r ect of the nine- 1957 // the interior of the rrect if the radii are >= 0.5. Otherwise, the inner r ect of the nine-
1830 // patch will have fractional coverage. This only matters when the interior is actually filled. 1958 // patch will have fractional coverage. This only matters when the interior is actually filled.
1831 // We could consider falling back to rect rendering here, since a tiny radiu s is 1959 // We could consider falling back to rect rendering here, since a tiny radiu s is
1832 // indistinguishable from a square corner. 1960 // indistinguishable from a square corner.
1833 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) { 1961 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) {
1834 return nullptr; 1962 return nullptr;
1835 } 1963 }
1836 1964
1837 // if the corners are circles, use the circle renderer 1965 // if the corners are circles, use the circle renderer
1838 if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius ) { 1966 if (isCircular) {
1839 return new RRectCircleRendererBatch(color, viewMatrix, bounds, xRadius, scaledStroke.fX, 1967 return new RRectCircleRendererBatch(color, viewMatrix, bounds, xRadius, scaledStroke.fX,
1840 isStrokeOnly); 1968 isStrokeOnly);
1841 // otherwise we use the ellipse renderer 1969 // otherwise we use the ellipse renderer
1842 } else { 1970 } else {
1843 return RRectEllipseRendererBatch::Create(color, viewMatrix, bounds, xRad ius, yRadius, 1971 return RRectEllipseRendererBatch::Create(color, viewMatrix, bounds, xRad ius, yRadius,
1844 scaledStroke, isStrokeOnly); 1972 scaledStroke, isStrokeOnly);
1845 1973
1846 } 1974 }
1847 } 1975 }
1848 1976
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
1962 } 2090 }
1963 2091
1964 DRAW_BATCH_TEST_DEFINE(RRectBatch) { 2092 DRAW_BATCH_TEST_DEFINE(RRectBatch) {
1965 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); 2093 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
1966 GrColor color = GrRandomColor(random); 2094 GrColor color = GrRandomColor(random);
1967 const SkRRect& rrect = GrTest::TestRRectSimple(random); 2095 const SkRRect& rrect = GrTest::TestRRectSimple(random);
1968 return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(ra ndom)); 2096 return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(ra ndom));
1969 } 2097 }
1970 2098
1971 #endif 2099 #endif
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698