OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |