Use SkVertices for tessellated spot and ambient shadow rendering.
Change-Id: Ia81e7a771d345286533752708e4304c1ae3b97c9
Reviewed-on: https://skia-review.googlesource.com/8042
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Stan Iliev <stani@google.com>
diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp
index b721f38..79567cc 100755
--- a/src/utils/SkShadowTessellator.cpp
+++ b/src/utils/SkShadowTessellator.cpp
@@ -9,40 +9,50 @@
#include "SkColorPriv.h"
#include "SkGeometry.h"
#include "SkPath.h"
+#include "SkVertices.h"
#if SK_SUPPORT_GPU
#include "GrPathUtils.h"
#endif
-template <typename T> using UniqueArray = SkShadowVertices::UniqueArray<T>;
/**
* Base class
*/
-class SkShadowTessellator {
+class SkBaseShadowTessellator {
public:
- SkShadowTessellator(SkScalar radius, SkColor umbraColor,
- SkColor penumbraColor, bool transparent);
- virtual ~SkShadowTessellator() {}
+ SkBaseShadowTessellator(SkScalar radius, SkColor umbraColor, SkColor penumbraColor,
+ bool transparent);
+ virtual ~SkBaseShadowTessellator() {}
- int vertexCount() const { return fPositions.count(); }
- int indexCount() const { return fIndices.count(); }
-
- bool succeeded() const { return fSucceeded; }
-
- // The casts are needed to work around a, older GCC issue where the fact that the pointers are
- // T* and not const T* causes calls to a deleted unique_ptr constructor.
- UniqueArray<SkPoint> releasePositions() {
- return UniqueArray<SkPoint>(static_cast<const SkPoint*>(fPositions.release()));
- }
- UniqueArray<SkColor> releaseColors() {
- return UniqueArray<SkColor>(static_cast<const SkColor*>(fColors.release()));
- }
- UniqueArray<uint16_t> releaseIndices() {
- return UniqueArray<uint16_t>(static_cast<const uint16_t*>(fIndices.release()));
+ sk_sp<SkVertices> releaseVertices() {
+ if (!fSucceeded) {
+ return nullptr;
+ }
+ int vCount = this->vertexCount();
+ int iCount = this->indexCount();
+ // We copy here for two reasons: 1) To tighten up our arrays and 2) to get into memory
+ // allocated by new[] rather than malloc.
+ // TODO: If we know we're not caching then we should avoid this.
+ SkPoint* positions = new SkPoint[vCount];
+ SkColor* colors = new SkColor[vCount];
+ uint16_t* indices = new uint16_t[iCount];
+ memcpy(positions, fPositions.begin(), sizeof(SkPoint) * vCount);
+ memcpy(colors, fColors.begin(), sizeof(SkColor) * vCount);
+ memcpy(indices, fIndices.begin(), sizeof(uint16_t) * iCount);
+ return SkVertices::MakeIndexed(SkCanvas::kTriangles_VertexMode,
+ std::unique_ptr<const SkPoint[]>(positions),
+ std::unique_ptr<const SkColor[]>(colors),
+ nullptr,
+ vCount,
+ std::unique_ptr<const uint16_t[]>(indices),
+ iCount);
}
protected:
+ int vertexCount() const { return fPositions.count(); }
+ int indexCount() const { return fIndices.count(); }
+
virtual void handleLine(const SkPoint& p) = 0;
void handleLine(const SkMatrix& m, SkPoint* p);
@@ -112,17 +122,16 @@
*n = SkScalarFloorToInt(steps);
}
-SkShadowTessellator::SkShadowTessellator(SkScalar radius, SkColor umbraColor,
- SkColor penumbraColor, bool transparent)
- : fFirstVertex(-1)
- , fSucceeded(false)
- , fTransparent(transparent)
- , fUmbraColor(umbraColor)
- , fPenumbraColor(penumbraColor)
- , fRadius(radius)
- , fDirection(1)
- , fPrevUmbraIndex(-1) {
-
+SkBaseShadowTessellator::SkBaseShadowTessellator(SkScalar radius, SkColor umbraColor,
+ SkColor penumbraColor, bool transparent)
+ : fFirstVertex(-1)
+ , fSucceeded(false)
+ , fTransparent(transparent)
+ , fUmbraColor(umbraColor)
+ , fPenumbraColor(penumbraColor)
+ , fRadius(radius)
+ , fDirection(1)
+ , fPrevUmbraIndex(-1) {
fInitPoints.setReserve(3);
// child classes will set reserve for positions, colors and indices
@@ -133,12 +142,12 @@
static const SkScalar kCubicTolerance = 0.2f;
static const SkScalar kConicTolerance = 0.5f;
-void SkShadowTessellator::handleLine(const SkMatrix& m, SkPoint* p) {
+void SkBaseShadowTessellator::handleLine(const SkMatrix& m, SkPoint* p) {
m.mapPoints(p, 1);
this->handleLine(*p);
}
-void SkShadowTessellator::handleQuad(const SkPoint pts[3]) {
+void SkBaseShadowTessellator::handleQuad(const SkPoint pts[3]) {
#if SK_SUPPORT_GPU
// TODO: Pull PathUtils out of Ganesh?
int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
@@ -157,12 +166,12 @@
#endif
}
-void SkShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) {
+void SkBaseShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) {
m.mapPoints(pts, 3);
this->handleQuad(pts);
}
-void SkShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) {
+void SkBaseShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) {
m.mapPoints(pts, 4);
#if SK_SUPPORT_GPU
// TODO: Pull PathUtils out of Ganesh?
@@ -183,7 +192,7 @@
#endif
}
-void SkShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) {
+void SkBaseShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) {
m.mapPoints(pts, 3);
SkAutoConicToQuads quadder;
const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
@@ -200,7 +209,7 @@
}
}
-void SkShadowTessellator::addArc(const SkVector& nextNormal) {
+void SkBaseShadowTessellator::addArc(const SkVector& nextNormal) {
// fill in fan from previous quad
SkScalar rotSin, rotCos;
int numSteps;
@@ -220,8 +229,8 @@
}
}
-void SkShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
- const SkVector& nextNormal) {
+void SkBaseShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
+ const SkVector& nextNormal) {
// close out previous arc
*fPositions.push() = fPrevPoint + nextNormal;
*fColors.push() = fPenumbraColor;
@@ -235,7 +244,7 @@
//////////////////////////////////////////////////////////////////////////////////////////////////
-class SkAmbientShadowTessellator : public SkShadowTessellator {
+class SkAmbientShadowTessellator : public SkBaseShadowTessellator {
public:
SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm,
SkScalar radius, SkColor umbraColor,
@@ -247,7 +256,7 @@
int fCentroidCount;
- typedef SkShadowTessellator INHERITED;
+ typedef SkBaseShadowTessellator INHERITED;
};
SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
@@ -435,7 +444,7 @@
///////////////////////////////////////////////////////////////////////////////////////////////////
-class SkSpotShadowTessellator : public SkShadowTessellator {
+class SkSpotShadowTessellator : public SkBaseShadowTessellator {
public:
SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
SkScalar scale, const SkVector& translate,
@@ -463,7 +472,7 @@
bool fFirstUmbraOutside;
bool fValidUmbra;
- typedef SkShadowTessellator INHERITED;
+ typedef SkBaseShadowTessellator INHERITED;
};
SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
@@ -475,7 +484,6 @@
, fPrevUmbraOutside(false)
, fFirstUmbraOutside(false)
, fValidUmbra(true) {
-
// TODO: calculate these better
// Penumbra ring: 3*numPts
// Umbra ring: numPts
@@ -948,33 +956,18 @@
///////////////////////////////////////////////////////////////////////////////////////////////////
-sk_sp<SkShadowVertices> SkShadowVertices::MakeAmbient(const SkPath& path, const SkMatrix& ctm,
- SkScalar radius, SkColor umbra,
- SkColor penumbra, bool transparent) {
+sk_sp<SkVertices> SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm,
+ SkScalar radius, SkColor umbra, SkColor penumbra,
+ bool transparent) {
SkAmbientShadowTessellator ambientTess(path, ctm, radius, umbra, penumbra, transparent);
- if (!ambientTess.succeeded()) {
- return nullptr;
- }
- int vcount = ambientTess.vertexCount();
- int icount = ambientTess.indexCount();
- return sk_sp<SkShadowVertices>(new SkShadowVertices(ambientTess.releasePositions(),
- ambientTess.releaseColors(),
- ambientTess.releaseIndices(), vcount,
- icount));
+ return ambientTess.releaseVertices();
}
-sk_sp<SkShadowVertices> SkShadowVertices::MakeSpot(const SkPath& path, const SkMatrix& ctm,
- SkScalar scale, const SkVector& translate,
- SkScalar radius, SkColor umbraColor,
- SkColor penumbraColor, bool transparent) {
+sk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm,
+ SkScalar scale, const SkVector& translate,
+ SkScalar radius, SkColor umbraColor,
+ SkColor penumbraColor, bool transparent) {
SkSpotShadowTessellator spotTess(path, ctm, scale, translate, radius, umbraColor,
penumbraColor, transparent);
- if (!spotTess.succeeded()) {
- return nullptr;
- }
- int vcount = spotTess.vertexCount();
- int icount = spotTess.indexCount();
- return sk_sp<SkShadowVertices>(new SkShadowVertices(spotTess.releasePositions(),
- spotTess.releaseColors(),
- spotTess.releaseIndices(), vcount, icount));
+ return spotTess.releaseVertices();
}
diff --git a/src/utils/SkShadowTessellator.h b/src/utils/SkShadowTessellator.h
index 875bb76..eb49bbe 100755
--- a/src/utils/SkShadowTessellator.h
+++ b/src/utils/SkShadowTessellator.h
@@ -8,68 +8,31 @@
#ifndef SkShadowTessellator_DEFINED
#define SkShadowTessellator_DEFINED
-#include "SkTDArray.h"
-#include "SkRefCnt.h"
-#include "SkPoint.h"
-
#include "SkColor.h"
+#include "SkPoint.h"
+#include "SkRefCnt.h"
class SkMatrix;
class SkPath;
+class SkVertices;
-class SkShadowVertices : public SkRefCnt {
-public:
- /**
- * This function generates an ambient shadow mesh for a path by walking the path, outsetting by
- * the radius, and setting inner and outer colors to umbraColor and penumbraColor, respectively.
- * If transparent is true, then the center of the ambient shadow will be filled in.
- */
- static sk_sp<SkShadowVertices> MakeAmbient(const SkPath& path, const SkMatrix& ctm,
- SkScalar radius, SkColor umbraColor,
- SkColor penumbraColor, bool transparent);
+namespace SkShadowTessellator {
+/**
+ * This function generates an ambient shadow mesh for a path by walking the path, outsetting by
+ * the radius, and setting inner and outer colors to umbraColor and penumbraColor, respectively.
+ * If transparent is true, then the center of the ambient shadow will be filled in.
+ */
+sk_sp<SkVertices> MakeAmbient(const SkPath& path, const SkMatrix& ctm, SkScalar radius,
+ SkColor umbraColor, SkColor penumbraColor, bool transparent);
- /**
- * This function generates a spot shadow mesh for a path by walking the transformed path,
- * further transforming by the scale and translation, and outsetting and insetting by a radius.
- * The center will be clipped against the original path unless transparent is true.
- */
- static sk_sp<SkShadowVertices> MakeSpot(const SkPath& path, const SkMatrix& ctm,
- SkScalar scale, const SkVector& translate,
- SkScalar radius, SkColor umbraColor,
- SkColor penumbraColor, bool transparent);
-
- int vertexCount() const { return fVertexCnt; }
- const SkPoint* positions() const { return fPositions.get(); }
- const SkColor* colors() const { return fColors.get(); }
-
- int indexCount() const { return fIndexCnt; }
- const uint16_t* indices() const { return fIndices.get(); }
-
- size_t size() const {
- return sizeof(*this) + fVertexCnt * (sizeof(SkPoint) + sizeof(SkColor)) +
- fIndexCnt * sizeof(uint16_t);
- }
-
-private:
- template<typename T> using Deleter = SkTDArray<SkPoint>::Deleter;
- template<typename T> using UniqueArray = std::unique_ptr<const T[], Deleter<T>>;
-
- SkShadowVertices(UniqueArray<SkPoint>&& positions, UniqueArray<SkColor>&& colors,
- UniqueArray<uint16_t>&& indices, int vertexCnt, int indexCnt)
- : fVertexCnt(vertexCnt)
- , fIndexCnt(indexCnt)
- , fPositions(std::move(positions))
- , fColors(std::move(colors))
- , fIndices(std::move(indices)) {
- SkASSERT(SkToBool(fPositions) && SkToBool(fColors) && SkToBool(vertexCnt) &&
- SkToBool(fIndices) && SkToBool(indexCnt));
- }
-
- int fVertexCnt;
- int fIndexCnt;
- UniqueArray<SkPoint> fPositions;
- UniqueArray<SkColor> fColors;
- UniqueArray<uint16_t> fIndices;
-};
+/**
+ * This function generates a spot shadow mesh for a path by walking the transformed path,
+ * further transforming by the scale and translation, and outsetting and insetting by a radius.
+ * The center will be clipped against the original path unless transparent is true.
+ */
+sk_sp<SkVertices> MakeSpot(const SkPath& path, const SkMatrix& ctm, SkScalar scale,
+ const SkVector& translate, SkScalar radius, SkColor umbraColor,
+ SkColor penumbraColor, bool transparent);
+}
#endif
diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp
index c4b4e3d..8374aef 100755
--- a/src/utils/SkShadowUtils.cpp
+++ b/src/utils/SkShadowUtils.cpp
@@ -13,6 +13,7 @@
#include "SkResourceCache.h"
#include "SkShadowTessellator.h"
#include "SkTLazy.h"
+#include "SkVertices.h"
#if SK_SUPPORT_GPU
#include "GrShape.h"
#include "effects/GrBlurredEdgeFragmentProcessor.h"
@@ -98,9 +99,9 @@
return true;
}
- sk_sp<SkShadowVertices> makeVertices(const SkPath& path, const SkMatrix& ctm) const {
- return SkShadowVertices::MakeAmbient(path, ctm, fRadius, fUmbraColor, fPenumbraColor,
- fTransparent);
+ sk_sp<SkVertices> makeVertices(const SkPath& path, const SkMatrix& ctm) const {
+ return SkShadowTessellator::MakeAmbient(path, ctm, fRadius, fUmbraColor, fPenumbraColor,
+ fTransparent);
}
};
@@ -148,10 +149,10 @@
return false;
}
- sk_sp<SkShadowVertices> makeVertices(const SkPath& path, const SkMatrix& ctm) const {
+ sk_sp<SkVertices> makeVertices(const SkPath& path, const SkMatrix& ctm) const {
bool transparent = OccluderType::kTransparent == fOccluderType;
- return SkShadowVertices::MakeSpot(path, ctm, fScale, fOffset, fRadius, fUmbraColor,
- fPenumbraColor, transparent);
+ return SkShadowTessellator::MakeSpot(path, ctm, fScale, fOffset, fRadius, fUmbraColor,
+ fPenumbraColor, transparent);
}
};
@@ -165,23 +166,23 @@
public:
size_t size() const { return fAmbientSet.size() + fSpotSet.size(); }
- sk_sp<SkShadowVertices> find(const AmbientVerticesFactory& ambient, const SkMatrix& matrix,
- SkVector* translate) const {
+ sk_sp<SkVertices> find(const AmbientVerticesFactory& ambient, const SkMatrix& matrix,
+ SkVector* translate) const {
return fAmbientSet.find(ambient, matrix, translate);
}
- sk_sp<SkShadowVertices> add(const SkPath& devPath, const AmbientVerticesFactory& ambient,
- const SkMatrix& matrix) {
+ sk_sp<SkVertices> add(const SkPath& devPath, const AmbientVerticesFactory& ambient,
+ const SkMatrix& matrix) {
return fAmbientSet.add(devPath, ambient, matrix);
}
- sk_sp<SkShadowVertices> find(const SpotVerticesFactory& spot, const SkMatrix& matrix,
- SkVector* translate) const {
+ sk_sp<SkVertices> find(const SpotVerticesFactory& spot, const SkMatrix& matrix,
+ SkVector* translate) const {
return fSpotSet.find(spot, matrix, translate);
}
- sk_sp<SkShadowVertices> add(const SkPath& devPath, const SpotVerticesFactory& spot,
- const SkMatrix& matrix) {
+ sk_sp<SkVertices> add(const SkPath& devPath, const SpotVerticesFactory& spot,
+ const SkMatrix& matrix) {
return fSpotSet.add(devPath, spot, matrix);
}
@@ -191,8 +192,8 @@
public:
size_t size() const { return fSize; }
- sk_sp<SkShadowVertices> find(const FACTORY& factory, const SkMatrix& matrix,
- SkVector* translate) const {
+ sk_sp<SkVertices> find(const FACTORY& factory, const SkMatrix& matrix,
+ SkVector* translate) const {
for (int i = 0; i < MAX_ENTRIES; ++i) {
if (fEntries[i].fFactory.isCompatible(factory, translate)) {
const SkMatrix& m = fEntries[i].fMatrix;
@@ -214,9 +215,8 @@
return nullptr;
}
- sk_sp<SkShadowVertices> add(const SkPath& devPath, const FACTORY& factory,
- const SkMatrix& matrix) {
- sk_sp<SkShadowVertices> vertices = factory.makeVertices(devPath, matrix);
+ sk_sp<SkVertices> add(const SkPath& path, const FACTORY& factory, const SkMatrix& matrix) {
+ sk_sp<SkVertices> vertices = factory.makeVertices(path, matrix);
if (!vertices) {
return nullptr;
}
@@ -237,7 +237,7 @@
private:
struct Entry {
FACTORY fFactory;
- sk_sp<SkShadowVertices> fVertices;
+ sk_sp<SkVertices> fVertices;
SkMatrix fMatrix;
};
Entry fEntries[MAX_ENTRIES];
@@ -277,8 +277,8 @@
sk_sp<CachedTessellations> refTessellations() const { return fTessellations; }
template <typename FACTORY>
- sk_sp<SkShadowVertices> find(const FACTORY& factory, const SkMatrix& matrix,
- SkVector* translate) const {
+ sk_sp<SkVertices> find(const FACTORY& factory, const SkMatrix& matrix,
+ SkVector* translate) const {
return fTessellations->find(factory, matrix, translate);
}
@@ -300,7 +300,7 @@
const SkMatrix* const fViewMatrix;
// If this is valid after Find is called then we found the vertices and they should be drawn
// with fTranslate applied.
- sk_sp<SkShadowVertices> fVertices;
+ sk_sp<SkVertices> fVertices;
SkVector fTranslate = {0, 0};
// If this is valid after Find then the caller should add the vertices to the tessellation set
@@ -385,7 +385,7 @@
SkResourceCache::Find(*key, FindVisitor<FACTORY>, &context);
}
- sk_sp<SkShadowVertices> vertices;
+ sk_sp<SkVertices> vertices;
const SkVector* translate;
static constexpr SkVector kZeroTranslate = {0, 0};
bool foundInCache = SkToBool(context.fVertices);
@@ -426,9 +426,7 @@
canvas->save();
canvas->translate(translate->fX, translate->fY);
}
- canvas->drawVertices(SkCanvas::kTriangles_VertexMode, vertices->vertexCount(),
- vertices->positions(), nullptr, vertices->colors(), vertices->indices(),
- vertices->indexCount(), paint);
+ canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
if (translate->fX || translate->fY) {
canvas->restore();
}