Chromium Code Reviews| 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 innerRadius = devRadius - halfWidth; |
| 1406 fStroked = innerRadius >= 0; | 1457 // TODO: if radius is really large this might just be a fill |
|
robertphillips
2016/08/25 12:55:42
I think, once GrShape is complete, the stroke->fil
jvanverth1
2016/08/25 14:02:52
Fixed until then.
| |
| 1458 fType = (innerRadius >= 0) ? kStroke_RRectType : kOverstroke_RRe ctType; | |
| 1407 } | 1459 } |
| 1408 outerRadius += halfWidth; | 1460 outerRadius += halfWidth; |
| 1409 bounds.outset(halfWidth, halfWidth); | 1461 bounds.outset(halfWidth, halfWidth); |
| 1410 } | 1462 } |
| 1411 | 1463 |
| 1412 // The radii are outset for two reasons. First, it allows the shader to simply perform | 1464 // 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. | 1465 // 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 | 1466 // 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 | 1467 // rendered and the outset ensures the box will cover all partially cove red by the rrect |
| 1416 // corners. | 1468 // corners. |
| 1417 outerRadius += SK_ScalarHalf; | 1469 outerRadius += SK_ScalarHalf; |
| 1418 innerRadius -= SK_ScalarHalf; | 1470 innerRadius -= SK_ScalarHalf; |
| 1419 | 1471 |
| 1420 this->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo); | 1472 this->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo); |
| 1421 | 1473 |
| 1422 // Expand the rect for aa to generate correct vertices. | 1474 // Expand the rect for aa to generate correct vertices. |
| 1423 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); | 1475 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); |
| 1424 | 1476 |
| 1425 fGeoData.emplace_back(Geometry { color, innerRadius, outerRadius, bounds }); | 1477 fGeoData.emplace_back(Geometry { color, innerRadius, outerRadius, bounds }); |
| 1426 } | 1478 } |
| 1427 | 1479 |
| 1428 const char* name() const override { return "RRectCircleBatch"; } | 1480 const char* name() const override { return "RRectCircleBatch"; } |
| 1429 | 1481 |
| 1482 SkString dumpInfo() const override { | |
| 1483 SkString string; | |
| 1484 for (int i = 0; i < fGeoData.count(); ++i) { | |
| 1485 string.appendf("Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %. 2f]," | |
| 1486 "InnerRad: %.2f, OuterRad: %.2f\n", | |
| 1487 fGeoData[i].fColor, | |
| 1488 fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds. fTop, | |
| 1489 fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds .fBottom, | |
| 1490 fGeoData[i].fInnerRadius, | |
| 1491 fGeoData[i].fOuterRadius); | |
| 1492 } | |
| 1493 string.append(INHERITED::dumpInfo()); | |
| 1494 return string; | |
| 1495 } | |
| 1496 | |
| 1430 void computePipelineOptimizations(GrInitInvariantOutput* color, | 1497 void computePipelineOptimizations(GrInitInvariantOutput* color, |
| 1431 GrInitInvariantOutput* coverage, | 1498 GrInitInvariantOutput* coverage, |
| 1432 GrBatchToXPOverrides* overrides) const ove rride { | 1499 GrBatchToXPOverrides* overrides) const ove rride { |
| 1433 // When this is called on a batch, there is only one geometry bundle | 1500 // When this is called on a batch, there is only one geometry bundle |
| 1434 color->setKnownFourComponents(fGeoData[0].fColor); | 1501 color->setKnownFourComponents(fGeoData[0].fColor); |
| 1435 coverage->setUnknownSingleComponent(); | 1502 coverage->setUnknownSingleComponent(); |
| 1436 } | 1503 } |
| 1437 | 1504 |
| 1438 private: | 1505 private: |
| 1439 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 1506 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
| 1440 // Handle any overrides that affect our GP. | 1507 // Handle any overrides that affect our GP. |
| 1441 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); | 1508 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); |
| 1442 if (!overrides.readsLocalCoords()) { | 1509 if (!overrides.readsLocalCoords()) { |
| 1443 fViewMatrixIfUsingLocalCoords.reset(); | 1510 fViewMatrixIfUsingLocalCoords.reset(); |
| 1444 } | 1511 } |
| 1445 } | 1512 } |
| 1446 | 1513 |
| 1447 void onPrepareDraws(Target* target) const override { | 1514 void onPrepareDraws(Target* target) const override { |
| 1448 // Invert the view matrix as a local matrix (if any other processors req uire coords). | 1515 // Invert the view matrix as a local matrix (if any other processors req uire coords). |
| 1449 SkMatrix localMatrix; | 1516 SkMatrix localMatrix; |
| 1450 if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) { | 1517 if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) { |
| 1451 return; | 1518 return; |
| 1452 } | 1519 } |
| 1453 | 1520 |
| 1454 // Setup geometry processor | 1521 // Setup geometry processor |
| 1455 SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(fStroke d, false, false, | 1522 SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(kStroke _RRectType == fType, |
| 1523 false, false, | |
| 1456 false, localMatrix)); | 1524 false, localMatrix)); |
| 1457 | 1525 |
| 1458 struct CircleVertex { | 1526 struct CircleVertex { |
| 1459 SkPoint fPos; | 1527 SkPoint fPos; |
| 1460 GrColor fColor; | 1528 GrColor fColor; |
| 1461 SkPoint fOffset; | 1529 SkPoint fOffset; |
| 1462 SkScalar fOuterRadius; | 1530 SkScalar fOuterRadius; |
| 1463 SkScalar fInnerRadius; | 1531 SkScalar fInnerRadius; |
| 1464 // No half plane, we don't use it here. | 1532 // No half plane, we don't use it here. |
| 1465 }; | 1533 }; |
| 1466 | 1534 |
| 1467 int instanceCount = fGeoData.count(); | 1535 int instanceCount = fGeoData.count(); |
| 1468 size_t vertexStride = gp->getVertexStride(); | 1536 size_t vertexStride = gp->getVertexStride(); |
| 1469 SkASSERT(vertexStride == sizeof(CircleVertex)); | 1537 SkASSERT(vertexStride == sizeof(CircleVertex)); |
| 1470 | 1538 |
| 1471 // drop out the middle quad if we're stroked | 1539 // drop out the middle quad if we're stroked |
| 1472 int indicesPerInstance = fStroked ? kIndicesPerStrokeRRect : kIndicesPer RRect; | 1540 int indicesPerInstance = kIndicesPerFillRRect; |
| 1541 if (kStroke_RRectType == fType) { | |
| 1542 indicesPerInstance = kIndicesPerStrokeRRect; | |
| 1543 } else if (kOverstroke_RRectType == fType) { | |
| 1544 indicesPerInstance = kIndicesPerOverstrokeRRect; | |
| 1545 } | |
| 1473 SkAutoTUnref<const GrBuffer> indexBuffer( | 1546 SkAutoTUnref<const GrBuffer> indexBuffer( |
| 1474 ref_rrect_index_buffer(fStroked, target->resourceProvider())); | 1547 ref_rrect_index_buffer(fType, target->resourceProvider())); |
| 1475 | 1548 |
| 1476 InstancedHelper helper; | 1549 InstancedHelper helper; |
| 1550 int vertexCount = (kOverstroke_RRectType == fType) ? kVertsPerOverstroke RRect | |
| 1551 : kVertsPerStandardRR ect; | |
| 1477 CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target , | 1552 CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target , |
| 1478 kTriangles_GrPrimitiveType, vertexStride, indexBuffer, kVertsPerRRec t, | 1553 kTriangles_GrPrimitiveType, vertexStride, indexBuffer, vertexCount, |
| 1479 indicesPerInstance, instanceCount)); | 1554 indicesPerInstance, instanceCount)); |
| 1480 if (!verts || !indexBuffer) { | 1555 if (!verts || !indexBuffer) { |
| 1481 SkDebugf("Could not allocate vertices\n"); | 1556 SkDebugf("Could not allocate vertices\n"); |
| 1482 return; | 1557 return; |
| 1483 } | 1558 } |
| 1484 | 1559 |
| 1485 for (int i = 0; i < instanceCount; i++) { | 1560 for (int i = 0; i < instanceCount; i++) { |
| 1486 const Geometry& args = fGeoData[i]; | 1561 const Geometry& args = fGeoData[i]; |
| 1487 | 1562 |
| 1488 GrColor color = args.fColor; | 1563 GrColor color = args.fColor; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1522 verts->fInnerRadius = innerRadius; | 1597 verts->fInnerRadius = innerRadius; |
| 1523 verts++; | 1598 verts++; |
| 1524 | 1599 |
| 1525 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); | 1600 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); |
| 1526 verts->fColor = color; | 1601 verts->fColor = color; |
| 1527 verts->fOffset = SkPoint::Make(1, yOuterRadii[i]); | 1602 verts->fOffset = SkPoint::Make(1, yOuterRadii[i]); |
| 1528 verts->fOuterRadius = outerRadius; | 1603 verts->fOuterRadius = outerRadius; |
| 1529 verts->fInnerRadius = innerRadius; | 1604 verts->fInnerRadius = innerRadius; |
| 1530 verts++; | 1605 verts++; |
| 1531 } | 1606 } |
| 1607 // Add the additional vertices for overstroked rrects. | |
| 1608 // | |
| 1609 // Note that args.fInnerRadius is negative in this case. | |
| 1610 // Also, the offset is a constant vector pointing to the right, whic h guarantees | |
| 1611 // that the distance value along the inner rectangle is constant, wh ich | |
| 1612 // is what we want to get nice anti-aliasing. | |
| 1613 if (kOverstroke_RRectType == fType) { | |
| 1614 // outerRadius = originalOuter + 0.5, and innerRadius = original Inner - 0.5. | |
| 1615 // What we want is originalOuter - originalInner + 0.5, so we su btract 0.5. | |
| 1616 SkScalar inset = outerRadius - args.fInnerRadius - SK_ScalarHalf ; | |
| 1617 verts->fPos = SkPoint::Make(bounds.fLeft + inset, | |
| 1618 bounds.fTop + inset); | |
| 1619 verts->fColor = color; | |
| 1620 verts->fOffset = SkPoint::Make(1, 0); | |
| 1621 verts->fOuterRadius = outerRadius; | |
| 1622 verts->fInnerRadius = innerRadius; | |
| 1623 verts++; | |
| 1624 | |
| 1625 verts->fPos = SkPoint::Make(bounds.fRight - inset, | |
| 1626 bounds.fTop + inset); | |
| 1627 verts->fColor = color; | |
| 1628 verts->fOffset = SkPoint::Make(1, 0); | |
| 1629 verts->fOuterRadius = outerRadius; | |
| 1630 verts->fInnerRadius = innerRadius; | |
| 1631 verts++; | |
| 1632 | |
| 1633 verts->fPos = SkPoint::Make(bounds.fLeft + inset, | |
| 1634 bounds.fBottom - inset); | |
| 1635 verts->fColor = color; | |
| 1636 verts->fOffset = SkPoint::Make(1, 0); | |
| 1637 verts->fOuterRadius = outerRadius; | |
| 1638 verts->fInnerRadius = innerRadius; | |
| 1639 verts++; | |
| 1640 | |
| 1641 verts->fPos = SkPoint::Make(bounds.fRight - inset, | |
| 1642 bounds.fBottom - inset); | |
| 1643 verts->fColor = color; | |
| 1644 verts->fOffset = SkPoint::Make(1, 0); | |
| 1645 verts->fOuterRadius = outerRadius; | |
| 1646 verts->fInnerRadius = innerRadius; | |
| 1647 verts++; | |
| 1648 } | |
| 1532 } | 1649 } |
| 1533 | 1650 |
| 1534 helper.recordDraw(target, gp); | 1651 helper.recordDraw(target, gp); |
| 1535 } | 1652 } |
| 1536 | 1653 |
| 1537 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { | 1654 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { |
| 1538 RRectCircleRendererBatch* that = t->cast<RRectCircleRendererBatch>(); | 1655 RRectCircleRendererBatch* that = t->cast<RRectCircleRendererBatch>(); |
| 1539 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(), | 1656 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(), |
| 1540 that->bounds(), caps)) { | 1657 that->bounds(), caps)) { |
| 1541 return false; | 1658 return false; |
| 1542 } | 1659 } |
| 1543 | 1660 |
| 1544 if (fStroked != that->fStroked) { | 1661 if (fType != that->fType) { |
| 1545 return false; | 1662 return false; |
| 1546 } | 1663 } |
| 1547 | 1664 |
| 1548 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) { | 1665 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) { |
| 1549 return false; | 1666 return false; |
| 1550 } | 1667 } |
| 1551 | 1668 |
| 1552 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); | 1669 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); |
| 1553 this->joinBounds(*that); | 1670 this->joinBounds(*that); |
| 1554 return true; | 1671 return true; |
| 1555 } | 1672 } |
| 1556 | 1673 |
| 1557 struct Geometry { | 1674 struct Geometry { |
| 1558 GrColor fColor; | 1675 GrColor fColor; |
| 1559 SkScalar fInnerRadius; | 1676 SkScalar fInnerRadius; |
| 1560 SkScalar fOuterRadius; | 1677 SkScalar fOuterRadius; |
| 1561 SkRect fDevBounds; | 1678 SkRect fDevBounds; |
| 1562 }; | 1679 }; |
| 1563 | 1680 |
| 1564 bool fStroked; | 1681 RRectType fType; |
| 1565 SkMatrix fViewMatrixIfUsingLocalCoords; | 1682 SkMatrix fViewMatrixIfUsingLocalCoords; |
| 1566 SkSTArray<1, Geometry, true> fGeoData; | 1683 SkSTArray<1, Geometry, true> fGeoData; |
| 1567 | 1684 |
| 1568 typedef GrVertexBatch INHERITED; | 1685 typedef GrVertexBatch INHERITED; |
| 1569 }; | 1686 }; |
| 1570 | 1687 |
| 1571 class RRectEllipseRendererBatch : public GrVertexBatch { | 1688 class RRectEllipseRendererBatch : public GrVertexBatch { |
| 1572 public: | 1689 public: |
| 1573 DEFINE_BATCH_CLASS_ID | 1690 DEFINE_BATCH_CLASS_ID |
| 1574 | 1691 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1659 } | 1776 } |
| 1660 | 1777 |
| 1661 // Setup geometry processor | 1778 // Setup geometry processor |
| 1662 SkAutoTUnref<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStrok ed, localMatrix)); | 1779 SkAutoTUnref<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStrok ed, localMatrix)); |
| 1663 | 1780 |
| 1664 int instanceCount = fGeoData.count(); | 1781 int instanceCount = fGeoData.count(); |
| 1665 size_t vertexStride = gp->getVertexStride(); | 1782 size_t vertexStride = gp->getVertexStride(); |
| 1666 SkASSERT(vertexStride == sizeof(EllipseVertex)); | 1783 SkASSERT(vertexStride == sizeof(EllipseVertex)); |
| 1667 | 1784 |
| 1668 // drop out the middle quad if we're stroked | 1785 // drop out the middle quad if we're stroked |
| 1669 int indicesPerInstance = fStroked ? kIndicesPerStrokeRRect : kIndicesPer RRect; | 1786 int indicesPerInstance = fStroked ? kIndicesPerStrokeRRect : kIndicesPer FillRRect; |
| 1670 SkAutoTUnref<const GrBuffer> indexBuffer( | 1787 SkAutoTUnref<const GrBuffer> indexBuffer( |
| 1671 ref_rrect_index_buffer(fStroked, target->resourceProvider())); | 1788 ref_rrect_index_buffer(fStroked ? kStroke_RRectType : kFill_RRectTyp e, |
| 1789 target->resourceProvider())); | |
| 1672 | 1790 |
| 1673 InstancedHelper helper; | 1791 InstancedHelper helper; |
| 1674 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>( | 1792 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>( |
| 1675 helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexB uffer, | 1793 helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexB uffer, |
| 1676 kVertsPerRRect, indicesPerInstance, instanceCount)); | 1794 kVertsPerStandardRRect, indicesPerInstance, instanceCoun t)); |
| 1677 if (!verts || !indexBuffer) { | 1795 if (!verts || !indexBuffer) { |
| 1678 SkDebugf("Could not allocate vertices\n"); | 1796 SkDebugf("Could not allocate vertices\n"); |
| 1679 return; | 1797 return; |
| 1680 } | 1798 } |
| 1681 | 1799 |
| 1682 for (int i = 0; i < instanceCount; i++) { | 1800 for (int i = 0; i < instanceCount; i++) { |
| 1683 const Geometry& args = fGeoData[i]; | 1801 const Geometry& args = fGeoData[i]; |
| 1684 | 1802 |
| 1685 GrColor color = args.fColor; | 1803 GrColor color = args.fColor; |
| 1686 | 1804 |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1802 SkStrokeRec::Style style = stroke.getStyle(); | 1920 SkStrokeRec::Style style = stroke.getStyle(); |
| 1803 | 1921 |
| 1804 // Do (potentially) anisotropic mapping of stroke. Use -1s to indicate fill- only draws. | 1922 // Do (potentially) anisotropic mapping of stroke. Use -1s to indicate fill- only draws. |
| 1805 SkVector scaledStroke = {-1, -1}; | 1923 SkVector scaledStroke = {-1, -1}; |
| 1806 SkScalar strokeWidth = stroke.getWidth(); | 1924 SkScalar strokeWidth = stroke.getWidth(); |
| 1807 | 1925 |
| 1808 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || | 1926 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || |
| 1809 SkStrokeRec::kHairline_Style == style; | 1927 SkStrokeRec::kHairline_Style == style; |
| 1810 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; | 1928 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style; |
| 1811 | 1929 |
| 1930 bool isCircular = (xRadius == yRadius); | |
| 1812 if (hasStroke) { | 1931 if (hasStroke) { |
| 1813 if (SkStrokeRec::kHairline_Style == style) { | 1932 if (SkStrokeRec::kHairline_Style == style) { |
| 1814 scaledStroke.set(1, 1); | 1933 scaledStroke.set(1, 1); |
| 1815 } else { | 1934 } else { |
| 1816 scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSc aleX] + | 1935 scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSc aleX] + |
| 1817 viewMatrix[SkMatrix::kMSk ewY])); | 1936 viewMatrix[SkMatrix::kMSk ewY])); |
| 1818 scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSk ewX] + | 1937 scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSk ewX] + |
| 1819 viewMatrix[SkMatrix::kMSc aleY])); | 1938 viewMatrix[SkMatrix::kMSc aleY])); |
| 1820 } | 1939 } |
| 1821 | 1940 |
| 1822 // if half of strokewidth is greater than radius, we don't handle that r ight now | 1941 isCircular = isCircular && scaledStroke.fX == scaledStroke.fY; |
| 1823 if (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStrok e.fY > yRadius) { | 1942 // for non-circular rrects, if half of strokewidth is greater than radiu s, |
| 1943 // we don't handle that right now | |
| 1944 if (!isCircular && | |
| 1945 (SK_ScalarHalf*scaledStroke.fX > xRadius || SK_ScalarHalf*scaledStro ke.fY > yRadius)) { | |
| 1824 return nullptr; | 1946 return nullptr; |
| 1825 } | 1947 } |
| 1826 } | 1948 } |
| 1827 | 1949 |
| 1828 // The way the effect interpolates the offset-to-ellipse/circle-center attri bute only works on | 1950 // 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- | 1951 // 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. | 1952 // 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 | 1953 // We could consider falling back to rect rendering here, since a tiny radiu s is |
| 1832 // indistinguishable from a square corner. | 1954 // indistinguishable from a square corner. |
| 1833 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) { | 1955 if (!isStrokeOnly && (SK_ScalarHalf > xRadius || SK_ScalarHalf > yRadius)) { |
| 1834 return nullptr; | 1956 return nullptr; |
| 1835 } | 1957 } |
| 1836 | 1958 |
| 1837 // if the corners are circles, use the circle renderer | 1959 // if the corners are circles, use the circle renderer |
| 1838 if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius ) { | 1960 if (isCircular) { |
| 1839 return new RRectCircleRendererBatch(color, viewMatrix, bounds, xRadius, scaledStroke.fX, | 1961 return new RRectCircleRendererBatch(color, viewMatrix, bounds, xRadius, scaledStroke.fX, |
| 1840 isStrokeOnly); | 1962 isStrokeOnly); |
| 1841 // otherwise we use the ellipse renderer | 1963 // otherwise we use the ellipse renderer |
| 1842 } else { | 1964 } else { |
| 1843 return RRectEllipseRendererBatch::Create(color, viewMatrix, bounds, xRad ius, yRadius, | 1965 return RRectEllipseRendererBatch::Create(color, viewMatrix, bounds, xRad ius, yRadius, |
| 1844 scaledStroke, isStrokeOnly); | 1966 scaledStroke, isStrokeOnly); |
| 1845 | 1967 |
| 1846 } | 1968 } |
| 1847 } | 1969 } |
| 1848 | 1970 |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1962 } | 2084 } |
| 1963 | 2085 |
| 1964 DRAW_BATCH_TEST_DEFINE(RRectBatch) { | 2086 DRAW_BATCH_TEST_DEFINE(RRectBatch) { |
| 1965 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); | 2087 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); |
| 1966 GrColor color = GrRandomColor(random); | 2088 GrColor color = GrRandomColor(random); |
| 1967 const SkRRect& rrect = GrTest::TestRRectSimple(random); | 2089 const SkRRect& rrect = GrTest::TestRRectSimple(random); |
| 1968 return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(ra ndom)); | 2090 return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(ra ndom)); |
| 1969 } | 2091 } |
| 1970 | 2092 |
| 1971 #endif | 2093 #endif |
| OLD | NEW |