aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/gpu/GrPath.cpp53
-rw-r--r--src/gpu/GrPath.h34
-rw-r--r--src/gpu/GrPathRange.cpp12
-rw-r--r--src/gpu/GrPathRange.h20
-rw-r--r--src/gpu/GrPathRendering.cpp19
-rw-r--r--src/gpu/GrPathRendering.h13
-rw-r--r--src/gpu/GrStencilAndCoverPathRenderer.cpp8
-rw-r--r--src/gpu/GrStencilAndCoverTextContext.cpp47
-rw-r--r--src/gpu/GrStencilAndCoverTextContext.h4
-rw-r--r--src/gpu/GrStrokeInfo.cpp54
-rw-r--r--src/gpu/GrStrokeInfo.h42
-rw-r--r--src/gpu/gl/GrGLPath.cpp30
-rw-r--r--src/gpu/gl/GrGLPath.h8
-rw-r--r--src/gpu/gl/GrGLPathRange.cpp51
-rw-r--r--src/gpu/gl/GrGLPathRange.h12
-rw-r--r--src/gpu/gl/GrGLPathRendering.cpp59
-rw-r--r--src/gpu/gl/GrGLPathRendering.h6
17 files changed, 302 insertions, 170 deletions
diff --git a/src/gpu/GrPath.cpp b/src/gpu/GrPath.cpp
index 3a66865c6e..e76bdf2466 100644
--- a/src/gpu/GrPath.cpp
+++ b/src/gpu/GrPath.cpp
@@ -7,49 +7,14 @@
#include "GrPath.h"
-template<int NumBits> static uint64_t get_top_n_float_bits(float f) {
- char* floatData = reinterpret_cast<char*>(&f);
- uint32_t floatBits = *reinterpret_cast<uint32_t*>(floatData);
- return floatBits >> (32 - NumBits);
-}
-
-void GrPath::ComputeKey(const SkPath& path, const SkStrokeRec& stroke, GrUniqueKey* key) {
- static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
- GrUniqueKey::Builder builder(key, kDomain, 3);
- *reinterpret_cast<uint64_t*>(&builder[0]) = ComputeStrokeKey(stroke);
- builder[2] = path.getGenerationID();
-}
-
-uint64_t GrPath::ComputeStrokeKey(const SkStrokeRec& stroke) {
- enum {
- kStyleBits = 2,
- kJoinBits = 2,
- kCapBits = 2,
- kWidthBits = 29,
- kMiterBits = 29,
-
- kJoinShift = kStyleBits,
- kCapShift = kJoinShift + kJoinBits,
- kWidthShift = kCapShift + kCapBits,
- kMiterShift = kWidthShift + kWidthBits,
-
- kBitCount = kMiterShift + kMiterBits
- };
-
- SK_COMPILE_ASSERT(SkStrokeRec::kStyleCount <= (1 << kStyleBits), style_shift_will_be_wrong);
- SK_COMPILE_ASSERT(SkPaint::kJoinCount <= (1 << kJoinBits), cap_shift_will_be_wrong);
- SK_COMPILE_ASSERT(SkPaint::kCapCount <= (1 << kCapBits), miter_shift_will_be_wrong);
- SK_COMPILE_ASSERT(kBitCount == 64, wrong_stroke_key_size);
-
- if (!stroke.needToApply()) {
- return SkStrokeRec::kFill_Style;
+void GrPath::ComputeKey(const SkPath& path, const GrStrokeInfo& stroke, GrUniqueKey* key) {
+ static const GrUniqueKey::Domain kPathDomain = GrUniqueKey::GenerateDomain();
+ int strokeDataCnt = stroke.computeUniqueKeyFragmentData32Cnt();
+ GrUniqueKey::Builder builder(key, kPathDomain, 2 + strokeDataCnt);
+ builder[0] = path.getGenerationID();
+ builder[1] = path.getFillType();
+ if (strokeDataCnt > 0) {
+ stroke.asUniqueKeyFragment(&builder[2]);
}
-
- uint64_t key = stroke.getStyle();
- key |= stroke.getJoin() << kJoinShift;
- key |= stroke.getCap() << kCapShift;
- key |= get_top_n_float_bits<kWidthBits>(stroke.getWidth()) << kWidthShift;
- key |= get_top_n_float_bits<kMiterBits>(stroke.getMiter()) << kMiterShift;
-
- return key;
}
+
diff --git a/src/gpu/GrPath.h b/src/gpu/GrPath.h
index ab8c51f2af..a535e697ca 100644
--- a/src/gpu/GrPath.h
+++ b/src/gpu/GrPath.h
@@ -9,9 +9,9 @@
#define GrPath_DEFINED
#include "GrGpuResource.h"
+#include "GrStrokeInfo.h"
#include "SkPath.h"
#include "SkRect.h"
-#include "SkStrokeRec.h"
class GrPath : public GrGpuResource {
public:
@@ -20,28 +20,32 @@ public:
/**
* Initialize to a path with a fixed stroke. Stroke must not be hairline.
*/
- GrPath(GrGpu* gpu, const SkPath& skPath, const SkStrokeRec& stroke)
- : INHERITED(gpu, kCached_LifeCycle),
- fSkPath(skPath),
- fStroke(stroke),
- fBounds(skPath.getBounds()) {
+ GrPath(GrGpu* gpu, const SkPath& skPath, const GrStrokeInfo& stroke)
+ : INHERITED(gpu, kCached_LifeCycle)
+ , fBounds(skPath.getBounds())
+#ifdef SK_DEBUG
+ , fSkPath(skPath)
+ , fStroke(stroke)
+#endif
+ {
}
- static void ComputeKey(const SkPath& path, const SkStrokeRec& stroke, GrUniqueKey* key);
- static uint64_t ComputeStrokeKey(const SkStrokeRec&);
-
- bool isEqualTo(const SkPath& path, const SkStrokeRec& stroke) {
- return fSkPath == path && fStroke.hasEqualEffect(stroke);
- }
+ static void ComputeKey(const SkPath& path, const GrStrokeInfo& stroke, GrUniqueKey* key);
const SkRect& getBounds() const { return fBounds; }
- const SkStrokeRec& getStroke() const { return fStroke; }
+#ifdef SK_DEBUG
+ bool isEqualTo(const SkPath& path, const GrStrokeInfo& stroke) {
+ return fSkPath == path && fStroke.hasEqualEffect(stroke);
+ }
+#endif
protected:
- SkPath fSkPath;
- SkStrokeRec fStroke;
SkRect fBounds;
+#ifdef SK_DEBUG
+ SkPath fSkPath;
+ GrStrokeInfo fStroke;
+#endif
private:
typedef GrGpuResource INHERITED;
diff --git a/src/gpu/GrPathRange.cpp b/src/gpu/GrPathRange.cpp
index 8bac750b44..5e71014ce8 100644
--- a/src/gpu/GrPathRange.cpp
+++ b/src/gpu/GrPathRange.cpp
@@ -13,23 +13,19 @@ enum {
};
GrPathRange::GrPathRange(GrGpu* gpu,
- PathGenerator* pathGenerator,
- const SkStrokeRec& stroke)
+ PathGenerator* pathGenerator)
: INHERITED(gpu, kCached_LifeCycle),
fPathGenerator(SkRef(pathGenerator)),
- fNumPaths(fPathGenerator->getNumPaths()),
- fStroke(stroke) {
+ fNumPaths(fPathGenerator->getNumPaths()) {
const int numGroups = (fNumPaths + kPathsPerGroup - 1) / kPathsPerGroup;
fGeneratedPaths.reset((numGroups + 7) / 8); // 1 bit per path group.
memset(&fGeneratedPaths.front(), 0, fGeneratedPaths.count());
}
GrPathRange::GrPathRange(GrGpu* gpu,
- int numPaths,
- const SkStrokeRec& stroke)
+ int numPaths)
: INHERITED(gpu, kCached_LifeCycle),
- fNumPaths(numPaths),
- fStroke(stroke) {
+ fNumPaths(numPaths) {
}
void GrPathRange::willDrawPaths(const void* indices, PathIndexType indexType, int count) const {
diff --git a/src/gpu/GrPathRange.h b/src/gpu/GrPathRange.h
index 86883e3c27..035837fc36 100644
--- a/src/gpu/GrPathRange.h
+++ b/src/gpu/GrPathRange.h
@@ -10,14 +10,13 @@
#include "GrGpuResource.h"
#include "SkRefCnt.h"
-#include "SkStrokeRec.h"
#include "SkTArray.h"
class SkPath;
class SkDescriptor;
/**
- * Represents a contiguous range of GPU path objects, all with a common stroke.
+ * Represents a contiguous range of GPU path objects.
* This object is immutable with the exception that individual paths may be
* initialized lazily.
*/
@@ -50,7 +49,9 @@ public:
public:
virtual int getNumPaths() = 0;
virtual void generatePath(int index, SkPath* out) = 0;
+#ifdef SK_DEBUG
virtual bool isEqualTo(const SkDescriptor&) const { return false; }
+#endif
virtual ~PathGenerator() {}
};
@@ -58,22 +59,22 @@ public:
* Initialize a lazy-loaded path range. This class will generate an SkPath and call
* onInitPath() for each path within the range before it is drawn for the first time.
*/
- GrPathRange(GrGpu*, PathGenerator*, const SkStrokeRec& stroke);
+ GrPathRange(GrGpu*, PathGenerator*);
/**
* Initialize an eager-loaded path range. The subclass is responsible for ensuring all
* the paths are initialized up front.
*/
- GrPathRange(GrGpu*, int numPaths, const SkStrokeRec& stroke);
-
- virtual bool isEqualTo(const SkDescriptor& desc) const {
- return NULL != fPathGenerator.get() && fPathGenerator->isEqualTo(desc);
- }
+ GrPathRange(GrGpu*, int numPaths);
int getNumPaths() const { return fNumPaths; }
- const SkStrokeRec& getStroke() const { return fStroke; }
const PathGenerator* getPathGenerator() const { return fPathGenerator.get(); }
+#ifdef SK_DEBUG
+ virtual bool isEqualTo(const SkDescriptor& desc) const {
+ return NULL != fPathGenerator.get() && fPathGenerator->isEqualTo(desc);
+ }
+#endif
protected:
// Initialize a path in the range before drawing. This is only called when
// fPathGenerator is non-null. The child class need not call didChangeGpuMemorySize(),
@@ -89,7 +90,6 @@ private:
mutable SkAutoTUnref<PathGenerator> fPathGenerator;
mutable SkTArray<uint8_t, true /*MEM_COPY*/> fGeneratedPaths;
const int fNumPaths;
- const SkStrokeRec fStroke;
typedef GrGpuResource INHERITED;
};
diff --git a/src/gpu/GrPathRendering.cpp b/src/gpu/GrPathRendering.cpp
index fba55d5e1e..e97d754a46 100644
--- a/src/gpu/GrPathRendering.cpp
+++ b/src/gpu/GrPathRendering.cpp
@@ -15,13 +15,18 @@
class GlyphGenerator : public GrPathRange::PathGenerator {
public:
GlyphGenerator(const SkTypeface& typeface, const SkDescriptor& desc)
- : fDesc(desc.copy()),
- fScalerContext(typeface.createScalerContext(fDesc)) {
+ : fScalerContext(typeface.createScalerContext(&desc))
+#ifdef SK_DEBUG
+ , fDesc(desc.copy())
+#endif
+ {
fFlipMatrix.setScale(1, -1);
}
virtual ~GlyphGenerator() {
+#ifdef SK_DEBUG
SkDescriptor::Free(fDesc);
+#endif
}
int getNumPaths() override {
@@ -36,20 +41,22 @@ public:
fScalerContext->getPath(skGlyph, out);
out->transform(fFlipMatrix); // Load glyphs with the inverted y-direction.
}
-
+#ifdef SK_DEBUG
bool isEqualTo(const SkDescriptor& desc) const override {
return fDesc->equals(desc);
}
-
+#endif
private:
- SkDescriptor* const fDesc;
const SkAutoTDelete<SkScalerContext> fScalerContext;
SkMatrix fFlipMatrix;
+#ifdef SK_DEBUG
+ SkDescriptor* const fDesc;
+#endif
};
GrPathRange* GrPathRendering::createGlyphs(const SkTypeface* typeface,
const SkDescriptor* desc,
- const SkStrokeRec& stroke) {
+ const GrStrokeInfo& stroke) {
if (NULL == typeface) {
typeface = SkTypeface::GetDefaultTypeface();
SkASSERT(NULL != typeface);
diff --git a/src/gpu/GrPathRendering.h b/src/gpu/GrPathRendering.h
index 3e2cfc6c9a..e198d694db 100644
--- a/src/gpu/GrPathRendering.h
+++ b/src/gpu/GrPathRendering.h
@@ -11,12 +11,12 @@
#include "SkPath.h"
#include "GrPathRange.h"
-class SkStrokeRec;
class SkDescriptor;
class SkTypeface;
class GrPath;
class GrGpu;
class GrStencilSettings;
+class GrStrokeInfo;
/**
* Abstract class wrapping HW path rendering API.
@@ -84,17 +84,17 @@ public:
* @param stroke the path stroke.
* @return a new path.
*/
- virtual GrPath* createPath(const SkPath&, const SkStrokeRec&) = 0;
+ virtual GrPath* createPath(const SkPath&, const GrStrokeInfo&) = 0;
/**
* Creates a range of gpu paths with a common stroke. The caller owns a ref on the
* returned path range which must be balanced by a call to unref.
*
* @param PathGenerator class that generates SkPath objects for each path in the range.
- * @param SkStrokeRec the common stroke applied to each path in the range.
+ * @param GrStrokeInfo the common stroke applied to each path in the range.
* @return a new path range.
*/
- virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*, const SkStrokeRec&) = 0;
+ virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStrokeInfo&) = 0;
/**
* Creates a range of glyph paths, indexed by glyph id. The glyphs will have an
@@ -117,14 +117,15 @@ public:
* including with the stroke information baked directly into
* the outlines.
*
- * @param SkStrokeRec Common stroke that the GPU will apply to every path. Note that
+ * @param GrStrokeInfo Common stroke that the GPU will apply to every path. Note that
* if the glyph outlines contain baked-in strokes from the font
* descriptor, the GPU stroke will be applied on top of those
* outlines.
*
* @return a new path range populated with glyphs.
*/
- virtual GrPathRange* createGlyphs(const SkTypeface*, const SkDescriptor*, const SkStrokeRec&) = 0;
+ virtual GrPathRange* createGlyphs(const SkTypeface*, const SkDescriptor*,
+ const GrStrokeInfo&) = 0;
virtual void stencilPath(const GrPath*, const GrStencilSettings&) = 0;
virtual void drawPath(const GrPath*, const GrStencilSettings&) = 0;
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.cpp b/src/gpu/GrStencilAndCoverPathRenderer.cpp
index bfb0f04155..e60bea215a 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/GrStencilAndCoverPathRenderer.cpp
@@ -60,7 +60,6 @@ bool GrStencilAndCoverPathRenderer::canDrawPath(const GrDrawTarget* target,
const GrStrokeInfo& stroke,
bool antiAlias) const {
return !stroke.isHairlineStyle() &&
- !stroke.isDashed() &&
!antiAlias && // doesn't do per-path AA, relies on the target having MSAA
pipelineBuilder->getStencil().isDisabled();
}
@@ -73,15 +72,17 @@ GrStencilAndCoverPathRenderer::onGetStencilSupport(const GrDrawTarget*,
return GrPathRenderer::kStencilOnly_StencilSupport;
}
-static GrPath* get_gr_path(GrGpu* gpu, const SkPath& skPath, const SkStrokeRec& stroke) {
+static GrPath* get_gr_path(GrGpu* gpu, const SkPath& skPath, const GrStrokeInfo& stroke) {
GrContext* ctx = gpu->getContext();
GrUniqueKey key;
GrPath::ComputeKey(skPath, stroke, &key);
SkAutoTUnref<GrPath> path(
static_cast<GrPath*>(ctx->resourceProvider()->findAndRefResourceByUniqueKey(key)));
- if (NULL == path || !path->isEqualTo(skPath, stroke)) {
+ if (NULL == path) {
path.reset(gpu->pathRendering()->createPath(skPath, stroke));
ctx->resourceProvider()->assignUniqueKeyToResource(key, path);
+ } else {
+ SkASSERT(path->isEqualTo(skPath, stroke));
}
return path.detach();
}
@@ -106,7 +107,6 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(GrDrawTarget* target,
bool antiAlias) {
SkASSERT(!antiAlias);
SkASSERT(!stroke.isHairlineStyle());
- SkASSERT(!stroke.isDashed());
SkASSERT(pipelineBuilder->getStencil().isDisabled());
SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke));
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index a2abfa7fa9..34319516d5 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -55,8 +55,10 @@ bool GrStencilAndCoverTextContext::canDraw(const GrRenderTarget* rt,
if (skPaint.getMaskFilter()) {
return false;
}
- if (skPaint.getPathEffect()) {
- return false;
+ if (SkPathEffect* pe = skPaint.getPathEffect()) {
+ if (pe->asADash(NULL) != SkPathEffect::kDash_DashType) {
+ return false;
+ }
}
// No hairlines unless we can map the 1 px width to the object space.
@@ -220,26 +222,27 @@ void GrStencilAndCoverTextContext::onDrawPosText(GrRenderTarget* rt,
static GrPathRange* get_gr_glyphs(GrContext* ctx,
const SkTypeface* typeface,
const SkDescriptor* desc,
- const SkStrokeRec& stroke) {
- static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
- GrUniqueKey key;
- GrUniqueKey::Builder builder(&key, kDomain, 4);
- struct GlyphKey {
- uint32_t fChecksum;
- uint32_t fTypeface;
- uint64_t fStroke;
- };
- GlyphKey* glyphKey = reinterpret_cast<GlyphKey*>(&builder[0]);
- glyphKey->fChecksum = desc ? desc->getChecksum() : 0;
- glyphKey->fTypeface = typeface ? typeface->uniqueID() : 0;
- glyphKey->fStroke = GrPath::ComputeStrokeKey(stroke);
+ const GrStrokeInfo& stroke) {
+
+ static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDomain();
+ int strokeDataCount = stroke.computeUniqueKeyFragmentData32Cnt();
+ GrUniqueKey glyphKey;
+ GrUniqueKey::Builder builder(&glyphKey, kPathGlyphDomain, 2 + strokeDataCount);
+ reinterpret_cast<uint32_t&>(builder[0]) = desc ? desc->getChecksum() : 0;
+ reinterpret_cast<uint32_t&>(builder[1]) = typeface ? typeface->uniqueID() : 0;
+ if (strokeDataCount > 0) {
+ stroke.asUniqueKeyFragment(&builder[2]);
+ }
builder.finish();
SkAutoTUnref<GrPathRange> glyphs(
- static_cast<GrPathRange*>(ctx->resourceProvider()->findAndRefResourceByUniqueKey(key)));
- if (NULL == glyphs || (NULL != desc && !glyphs->isEqualTo(*desc))) {
+ static_cast<GrPathRange*>(
+ ctx->resourceProvider()->findAndRefResourceByUniqueKey(glyphKey)));
+ if (NULL == glyphs) {
glyphs.reset(ctx->getGpu()->pathRendering()->createGlyphs(typeface, desc, stroke));
- ctx->resourceProvider()->assignUniqueKeyToResource(key, glyphs);
+ ctx->resourceProvider()->assignUniqueKeyToResource(glyphKey, glyphs);
+ } else {
+ SkASSERT(NULL == desc || glyphs->isEqualTo(*desc));
}
return glyphs.detach();
@@ -273,7 +276,7 @@ void GrStencilAndCoverTextContext::init(GrRenderTarget* rt,
// The whole shape (including stroke) will be baked into the glyph outlines. Make
// NVPR just fill the baked shapes.
- fStroke = SkStrokeRec(SkStrokeRec::kFill_InitStyle);
+ fStroke = GrStrokeInfo(SkStrokeRec::kFill_InitStyle);
fTextRatio = fTextInverseRatio = 1.0f;
@@ -298,7 +301,7 @@ void GrStencilAndCoverTextContext::init(GrRenderTarget* rt,
} else {
// Don't bake strokes into the glyph outlines. We will stroke the glyphs
// using the GPU instead. This is the fast path.
- fStroke = SkStrokeRec(fSkPaint);
+ fStroke = GrStrokeInfo(fSkPaint);
fSkPaint.setStyle(SkPaint::kFill_Style);
if (fStroke.isHairlineStyle()) {
@@ -327,8 +330,8 @@ void GrStencilAndCoverTextContext::init(GrRenderTarget* rt,
}
bool canUseRawPaths;
-
- if (otherBackendsWillDrawAsPaths || kMaxPerformance_RenderMode == renderMode) {
+ if (!fStroke.isDashed() && (otherBackendsWillDrawAsPaths ||
+ kMaxPerformance_RenderMode == renderMode)) {
// We can draw the glyphs from canonically sized paths.
fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize();
diff --git a/src/gpu/GrStencilAndCoverTextContext.h b/src/gpu/GrStencilAndCoverTextContext.h
index d3d2470f26..0cb55535c2 100644
--- a/src/gpu/GrStencilAndCoverTextContext.h
+++ b/src/gpu/GrStencilAndCoverTextContext.h
@@ -10,7 +10,7 @@
#include "GrTextContext.h"
#include "GrDrawTarget.h"
-#include "SkStrokeRec.h"
+#include "GrStrokeInfo.h"
class GrTextStrike;
class GrPath;
@@ -58,7 +58,7 @@ private:
float fTextInverseRatio;
SkGlyphCache* fGlyphCache;
GrPathRange* fGlyphs;
- SkStrokeRec fStroke;
+ GrStrokeInfo fStroke;
uint16_t fGlyphIndices[kGlyphBufferSize];
SkPoint fGlyphPositions[kGlyphBufferSize];
int fQueuedGlyphCount;
diff --git a/src/gpu/GrStrokeInfo.cpp b/src/gpu/GrStrokeInfo.cpp
index eb3008bb37..0ad4179add 100644
--- a/src/gpu/GrStrokeInfo.cpp
+++ b/src/gpu/GrStrokeInfo.cpp
@@ -6,7 +6,7 @@
*/
#include "GrStrokeInfo.h"
-
+#include "GrResourceKey.h"
#include "SkDashPathPriv.h"
bool GrStrokeInfo::applyDashToPath(SkPath* dst, GrStrokeInfo* dstStrokeInfo,
@@ -24,3 +24,55 @@ bool GrStrokeInfo::applyDashToPath(SkPath* dst, GrStrokeInfo* dstStrokeInfo,
}
return false;
}
+
+void GrStrokeInfo::asUniqueKeyFragment(uint32_t* data) const {
+ const int kSkScalarData32Cnt = sizeof(SkScalar) / sizeof(uint32_t);
+ enum {
+ kStyleBits = 2,
+ kJoinBits = 2,
+ kCapBits = 32 - kStyleBits - kJoinBits,
+
+ kJoinShift = kStyleBits,
+ kCapShift = kJoinShift + kJoinBits,
+ };
+
+ SK_COMPILE_ASSERT(SkStrokeRec::kStyleCount <= (1 << kStyleBits), style_shift_will_be_wrong);
+ SK_COMPILE_ASSERT(SkPaint::kJoinCount <= (1 << kJoinBits), cap_shift_will_be_wrong);
+ SK_COMPILE_ASSERT(SkPaint::kCapCount <= (1 << kCapBits), cap_does_not_fit);
+ uint32_t styleKey = this->getStyle();
+ if (this->needToApply()) {
+ styleKey |= this->getJoin() << kJoinShift;
+ styleKey |= this->getCap() << kCapShift;
+ }
+ int i = 0;
+ data[i++] = styleKey;
+
+ // Memcpy the scalar fields. Does not "reinterpret_cast<SkScalar&>(data[i]) = ..." due to
+ // scalars having more strict alignment requirements than what data can guarantee. The
+ // compiler should optimize memcpys to assignments.
+ SkScalar scalar;
+ scalar = this->getMiter();
+ memcpy(&data[i], &scalar, sizeof(scalar));
+ i += kSkScalarData32Cnt;
+
+ scalar = this->getWidth();
+ memcpy(&data[i], &scalar, sizeof(scalar));
+ i += kSkScalarData32Cnt;
+
+ if (this->isDashed()) {
+ SkScalar phase = this->getDashPhase();
+ memcpy(&data[i], &phase, sizeof(phase));
+ i += kSkScalarData32Cnt;
+
+ int32_t count = this->getDashCount() & static_cast<int32_t>(~1);
+ SkASSERT(count == this->getDashCount());
+ const SkScalar* intervals = this->getDashIntervals();
+ int intervalByteCnt = count * sizeof(SkScalar);
+ memcpy(&data[i], intervals, intervalByteCnt);
+ // Enable the line below if fields are added after dashing.
+ SkDEBUGCODE(i += kSkScalarData32Cnt * count);
+ }
+
+ SkASSERT(this->computeUniqueKeyFragmentData32Cnt() == i);
+}
+
diff --git a/src/gpu/GrStrokeInfo.h b/src/gpu/GrStrokeInfo.h
index 5ba3cfe91d..1cc2dfe11b 100644
--- a/src/gpu/GrStrokeInfo.h
+++ b/src/gpu/GrStrokeInfo.h
@@ -11,6 +11,8 @@
#include "SkStrokeRec.h"
#include "SkPathEffect.h"
+class GrUniqueKey;
+
/*
* GrStrokeInfo encapsulates all the pertinent infomation regarding the stroke. The SkStrokeRec
* which holds information on fill style, width, miter, cap, and join. It also holds information
@@ -60,6 +62,21 @@ public:
return *this;
}
+ bool hasEqualEffect(const GrStrokeInfo& other) const {
+ if (this->isDashed() != other.isDashed()) {
+ return false;
+ }
+ if (this->isDashed()) {
+ if (fDashPhase != other.fDashPhase ||
+ fIntervals.count() != other.fIntervals.count() ||
+ memcmp(fIntervals.get(), other.fIntervals.get(),
+ fIntervals.count() * sizeof(SkScalar)) != 0) {
+ return false;
+ }
+ }
+ return this->INHERITED::hasEqualEffect(other);
+ }
+
/*
* This functions takes in a patheffect and updates the dashing information if the path effect
* is a Dash type. Returns true if the path effect is a dashed effect and we are stroking,
@@ -127,8 +144,31 @@ public:
*/
bool applyDashToPath(SkPath* dst, GrStrokeInfo* dstStrokeInfo, const SkPath& src) const;
+ /**
+ * Computes the length of the data that will be written by asUniqueKeyFragment() function.
+ */
+ int computeUniqueKeyFragmentData32Cnt() const {
+ const int kSkScalarData32Cnt = sizeof(SkScalar) / sizeof(uint32_t);
+ // SkStrokeRec data: 32 bits for style+join+cap and 2 scalars for miter and width.
+ int strokeKeyData32Cnt = 1 + 2 * kSkScalarData32Cnt;
+
+ if (this->isDashed()) {
+ // One scalar for dash phase and one for each dash value.
+ strokeKeyData32Cnt += (1 + this->getDashCount()) * kSkScalarData32Cnt;
+ }
+ return strokeKeyData32Cnt;
+ }
+
+ /**
+ * Writes the object contents as uint32_t data, to be used with GrUniqueKey.
+ * Note: the data written does not encode the length, so care must be taken to ensure
+ * that the full unique key data is encoded properly. For example, GrStrokeInfo
+ * fragment can be placed last in the sequence, at fixed index.
+ */
+ void asUniqueKeyFragment(uint32_t*) const;
+
private:
- // Prevent accidental usage, not implemented for GrStrokeInfos.
+ // Prevent accidental usage, should use GrStrokeInfo::hasEqualEffect.
bool hasEqualEffect(const SkStrokeRec& other) const;
void init(const SkPaint& paint) {
diff --git a/src/gpu/gl/GrGLPath.cpp b/src/gpu/gl/GrGLPath.cpp
index 037134aad4..80c6356cdd 100644
--- a/src/gpu/gl/GrGLPath.cpp
+++ b/src/gpu/gl/GrGLPath.cpp
@@ -91,7 +91,8 @@ inline void points_to_coords(const SkPoint points[], size_t first_point, size_t
void GrGLPath::InitPathObject(GrGLGpu* gpu,
GrGLuint pathID,
const SkPath& skPath,
- const SkStrokeRec& stroke) {
+ const GrStrokeInfo& stroke) {
+ SkASSERT(!stroke.isDashed());
if (!skPath.isEmpty()) {
int verbCnt = skPath.countVerbs();
int pointCnt = skPath.countPoints();
@@ -182,16 +183,33 @@ void GrGLPath::InitPathObject(GrGLGpu* gpu,
}
}
-GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& path, const SkStrokeRec& stroke)
- : INHERITED(gpu, path, stroke),
+GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& origStroke)
+ : INHERITED(gpu, origSkPath, origStroke),
fPathID(gpu->glPathRendering()->genPaths(1)) {
+ // Convert a dashing to either a stroke or a fill.
+ const SkPath* skPath = &origSkPath;
+ SkTLazy<SkPath> tmpPath;
+ const GrStrokeInfo* stroke = &origStroke;
+ GrStrokeInfo tmpStroke(SkStrokeRec::kFill_InitStyle);
+
+ if (stroke->isDashed()) {
+ if (stroke->applyDashToPath(tmpPath.init(), &tmpStroke, *skPath)) {
+ skPath = tmpPath.get();
+ stroke = &tmpStroke;
+ }
+ }
- InitPathObject(gpu, fPathID, fSkPath, stroke);
+ InitPathObject(gpu, fPathID, *skPath, *stroke);
- if (stroke.needToApply()) {
+ fShouldStroke = stroke->needToApply();
+ fShouldFill = stroke->isFillStyle() ||
+ stroke->getStyle() == SkStrokeRec::kStrokeAndFill_Style;
+
+ if (fShouldStroke) {
// FIXME: try to account for stroking, without rasterizing the stroke.
- fBounds.outset(stroke.getWidth(), stroke.getWidth());
+ fBounds.outset(stroke->getWidth(), stroke->getWidth());
}
+
this->registerWithCache();
}
diff --git a/src/gpu/gl/GrGLPath.h b/src/gpu/gl/GrGLPath.h
index f02f7052d5..b394050277 100644
--- a/src/gpu/gl/GrGLPath.h
+++ b/src/gpu/gl/GrGLPath.h
@@ -25,11 +25,13 @@ public:
static void InitPathObject(GrGLGpu*,
GrGLuint pathID,
const SkPath&,
- const SkStrokeRec&);
+ const GrStrokeInfo&);
- GrGLPath(GrGLGpu* gpu, const SkPath& path, const SkStrokeRec& stroke);
+ GrGLPath(GrGLGpu* gpu, const SkPath& path, const GrStrokeInfo& stroke);
GrGLuint pathID() const { return fPathID; }
+ bool shouldStroke() const { return fShouldStroke; }
+ bool shouldFill() const { return fShouldFill; }
protected:
void onRelease() override;
void onAbandon() override;
@@ -39,6 +41,8 @@ private:
size_t onGpuMemorySize() const override { return 100; }
GrGLuint fPathID;
+ bool fShouldStroke;
+ bool fShouldFill;
typedef GrPath INHERITED;
};
diff --git a/src/gpu/gl/GrGLPathRange.cpp b/src/gpu/gl/GrGLPathRange.cpp
index d7ccf1bcc7..b577d89619 100644
--- a/src/gpu/gl/GrGLPathRange.cpp
+++ b/src/gpu/gl/GrGLPathRange.cpp
@@ -11,10 +11,12 @@
#include "GrGLPathRendering.h"
#include "GrGLGpu.h"
-GrGLPathRange::GrGLPathRange(GrGLGpu* gpu, PathGenerator* pathGenerator, const SkStrokeRec& stroke)
- : INHERITED(gpu, pathGenerator, stroke),
+GrGLPathRange::GrGLPathRange(GrGLGpu* gpu, PathGenerator* pathGenerator, const GrStrokeInfo& stroke)
+ : INHERITED(gpu, pathGenerator),
+ fStroke(stroke),
fBasePathID(gpu->glPathRendering()->genPaths(this->getNumPaths())),
fGpuMemorySize(0) {
+ this->init();
this->registerWithCache();
}
@@ -22,14 +24,27 @@ GrGLPathRange::GrGLPathRange(GrGLGpu* gpu,
GrGLuint basePathID,
int numPaths,
size_t gpuMemorySize,
- const SkStrokeRec& stroke)
- : INHERITED(gpu, numPaths, stroke),
+ const GrStrokeInfo& stroke)
+ : INHERITED(gpu, numPaths),
+ fStroke(stroke),
fBasePathID(basePathID),
fGpuMemorySize(gpuMemorySize) {
+ this->init();
this->registerWithCache();
}
-void GrGLPathRange::onInitPath(int index, const SkPath& skPath) const {
+void GrGLPathRange::init() {
+ if (fStroke.isDashed()) {
+ fShouldStroke = false;
+ fShouldFill = true;
+ } else {
+ fShouldStroke = fStroke.needToApply();
+ fShouldFill = fStroke.isFillStyle() ||
+ fStroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style;
+ }
+}
+
+void GrGLPathRange::onInitPath(int index, const SkPath& origSkPath) const {
GrGLGpu* gpu = static_cast<GrGLGpu*>(this->getGpu());
if (NULL == gpu) {
return;
@@ -41,7 +56,31 @@ void GrGLPathRange::onInitPath(int index, const SkPath& skPath) const {
GR_GL_CALL_RET(gpu->glInterface(), isPath, IsPath(fBasePathID + index)));
SkASSERT(GR_GL_FALSE == isPath);
- GrGLPath::InitPathObject(gpu, fBasePathID + index, skPath, this->getStroke());
+ const SkPath* skPath = &origSkPath;
+ SkTLazy<SkPath> tmpPath;
+ const GrStrokeInfo* stroke = &fStroke;
+ GrStrokeInfo tmpStroke(SkStrokeRec::kFill_InitStyle);
+
+ // Dashing must be applied to the path. However, if dashing is present,
+ // we must convert all the paths to fills. The GrStrokeInfo::applyDash leaves
+ // simple paths as strokes but converts other paths to fills.
+ // Thus we must stroke the strokes here, so that all paths in the
+ // path range are using the same style.
+ if (fStroke.isDashed()) {
+ if (!stroke->applyDashToPath(tmpPath.init(), &tmpStroke, *skPath)) {
+ return;
+ }
+ skPath = tmpPath.get();
+ stroke = &tmpStroke;
+ if (tmpStroke.needToApply()) {
+ if (!tmpStroke.applyToPath(tmpPath.get(), *tmpPath.get())) {
+ return;
+ }
+ tmpStroke.setFillStyle();
+ }
+ }
+
+ GrGLPath::InitPathObject(gpu, fBasePathID + index, *skPath, *stroke);
// TODO: Use a better approximation for the individual path sizes.
fGpuMemorySize += 100;
diff --git a/src/gpu/gl/GrGLPathRange.h b/src/gpu/gl/GrGLPathRange.h
index 5cba9c79d7..22dd1c0572 100644
--- a/src/gpu/gl/GrGLPathRange.h
+++ b/src/gpu/gl/GrGLPathRange.h
@@ -10,6 +10,7 @@
#define GrGLPathRange_DEFINED
#include "../GrPathRange.h"
+#include "GrStrokeInfo.h"
#include "gl/GrGLFunctions.h"
class GrGLGpu;
@@ -26,7 +27,7 @@ public:
* Initialize a GL path range from a PathGenerator. This class will allocate
* the GPU path objects and initialize them lazily.
*/
- GrGLPathRange(GrGLGpu*, PathGenerator*, const SkStrokeRec&);
+ GrGLPathRange(GrGLGpu*, PathGenerator*, const GrStrokeInfo&);
/**
* Initialize a GL path range from an existing range of pre-initialized GPU
@@ -37,10 +38,13 @@ public:
GrGLuint basePathID,
int numPaths,
size_t gpuMemorySize,
- const SkStrokeRec&);
+ const GrStrokeInfo&);
GrGLuint basePathID() const { return fBasePathID; }
+ bool shouldStroke() const { return fShouldStroke; }
+ bool shouldFill() const { return fShouldFill; }
+
protected:
void onInitPath(int index, const SkPath&) const override;
@@ -48,10 +52,14 @@ protected:
void onAbandon() override;
private:
+ void init();
size_t onGpuMemorySize() const override { return fGpuMemorySize; }
+ const GrStrokeInfo fStroke;
GrGLuint fBasePathID;
mutable size_t fGpuMemorySize;
+ bool fShouldStroke;
+ bool fShouldFill;
typedef GrPathRange INHERITED;
};
diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
index 8a0b35c661..3ceb87692a 100644
--- a/src/gpu/gl/GrGLPathRendering.cpp
+++ b/src/gpu/gl/GrGLPathRendering.cpp
@@ -91,19 +91,19 @@ void GrGLPathRendering::resetContext() {
fHWPathStencilSettings.invalidate();
}
-GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const SkStrokeRec& stroke) {
+GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const GrStrokeInfo& stroke) {
return SkNEW_ARGS(GrGLPath, (fGpu, inPath, stroke));
}
GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
- const SkStrokeRec& stroke) {
+ const GrStrokeInfo& stroke) {
return SkNEW_ARGS(GrGLPathRange, (fGpu, pathGenerator, stroke));
}
GrPathRange* GrGLPathRendering::createGlyphs(const SkTypeface* typeface,
const SkDescriptor* desc,
- const SkStrokeRec& stroke) {
- if (NULL != desc || !caps().glyphLoadingSupport) {
+ const GrStrokeInfo& stroke) {
+ if (NULL != desc || !caps().glyphLoadingSupport || stroke.isDashed()) {
return GrPathRendering::createGlyphs(typeface, desc, stroke);
}
@@ -152,44 +152,40 @@ GrPathRange* GrGLPathRendering::createGlyphs(const SkTypeface* typeface,
}
void GrGLPathRendering::stencilPath(const GrPath* path, const GrStencilSettings& stencilSettings) {
- GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
+ const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
this->flushPathStencilSettings(stencilSettings);
SkASSERT(!fHWPathStencilSettings.isTwoSided());
- const SkStrokeRec& stroke = path->getStroke();
-
- GrGLenum fillMode =
- gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
+ GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
+ fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
- if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
- GL_CALL(StencilFillPath(id, fillMode, writeMask));
+ if (glPath->shouldFill()) {
+ GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
}
- if (stroke.needToApply()) {
- GL_CALL(StencilStrokePath(id, 0xffff, writeMask));
+ if (glPath->shouldStroke()) {
+ GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask));
}
}
void GrGLPathRendering::drawPath(const GrPath* path, const GrStencilSettings& stencilSettings) {
- GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
+ const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
this->flushPathStencilSettings(stencilSettings);
SkASSERT(!fHWPathStencilSettings.isTwoSided());
- const SkStrokeRec& stroke = path->getStroke();
-
- GrGLenum fillMode =
- gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
+ GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
+ fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
- if (stroke.needToApply()) {
- if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
- GL_CALL(StencilFillPath(id, fillMode, writeMask));
+ if (glPath->shouldStroke()) {
+ if (glPath->shouldFill()) {
+ GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
}
- this->stencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX);
+ this->stencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask, GR_GL_BOUNDING_BOX);
} else {
- this->stencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX);
+ this->stencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask, GR_GL_BOUNDING_BOX);
}
}
@@ -199,32 +195,31 @@ void GrGLPathRendering::drawPaths(const GrPathRange* pathRange,
int count, const GrStencilSettings& stencilSettings) {
SkASSERT(fGpu->caps()->shaderCaps()->pathRenderingSupport());
- GrGLuint baseID = static_cast<const GrGLPathRange*>(pathRange)->basePathID();
+ const GrGLPathRange* glPathRange = static_cast<const GrGLPathRange*>(pathRange);
this->flushPathStencilSettings(stencilSettings);
SkASSERT(!fHWPathStencilSettings.isTwoSided());
- const SkStrokeRec& stroke = pathRange->getStroke();
-
GrGLenum fillMode =
gr_stencil_op_to_gl_path_rendering_fill_mode(
fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
GrGLint writeMask =
fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
- if (stroke.needToApply()) {
- if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
+ if (glPathRange->shouldStroke()) {
+ if (glPathRange->shouldFill()) {
GL_CALL(StencilFillPathInstanced(
- count, gIndexType2GLType[indexType], indices, baseID, fillMode,
- writeMask, gXformType2GLType[transformType], transformValues));
+ count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
+ fillMode, writeMask, gXformType2GLType[transformType],
+ transformValues));
}
this->stencilThenCoverStrokePathInstanced(
- count, gIndexType2GLType[indexType], indices, baseID,
+ count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
0xffff, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
gXformType2GLType[transformType], transformValues);
} else {
this->stencilThenCoverFillPathInstanced(
- count, gIndexType2GLType[indexType], indices, baseID,
+ count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
fillMode, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
gXformType2GLType[transformType], transformValues);
}
diff --git a/src/gpu/gl/GrGLPathRendering.h b/src/gpu/gl/GrGLPathRendering.h
index 25e8ef03ef..84bac6c117 100644
--- a/src/gpu/gl/GrGLPathRendering.h
+++ b/src/gpu/gl/GrGLPathRendering.h
@@ -33,12 +33,12 @@ public:
virtual ~GrGLPathRendering();
// GrPathRendering implementations.
- GrPath* createPath(const SkPath&, const SkStrokeRec&) override;
+ GrPath* createPath(const SkPath&, const GrStrokeInfo&) override;
virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*,
- const SkStrokeRec&) override;
+ const GrStrokeInfo&) override;
virtual GrPathRange* createGlyphs(const SkTypeface*,
const SkDescriptor*,
- const SkStrokeRec&) override;
+ const GrStrokeInfo&) override;
void stencilPath(const GrPath*, const GrStencilSettings&) override;
void drawPath(const GrPath*, const GrStencilSettings&) override;
virtual void drawPaths(const GrPathRange*, const void* indices, PathIndexType,