aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/gpu/GrAAConvexPathRenderer.cpp17
-rw-r--r--src/gpu/GrAAConvexPathRenderer.h6
-rw-r--r--src/gpu/GrAAHairLinePathRenderer.cpp15
-rw-r--r--src/gpu/GrAAHairLinePathRenderer.h6
-rw-r--r--src/gpu/GrClipMaskManager.cpp202
-rw-r--r--src/gpu/GrClipMaskManager.h2
-rw-r--r--src/gpu/GrSoftwarePathRenderer.cpp31
-rw-r--r--src/gpu/GrSoftwarePathRenderer.h13
8 files changed, 248 insertions, 44 deletions
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index ca7ecdcb4a..3da4af2def 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -430,19 +430,26 @@ void create_vertices(const SegmentArray& segments,
}
-bool GrAAConvexPathRenderer::canDrawPath(const SkPath& path,
- GrPathFill fill,
- const GrDrawTarget* target,
- bool antiAlias) const {
+bool GrAAConvexPathRenderer::staticCanDrawPath(bool pathIsConvex,
+ GrPathFill fill,
+ const GrDrawTarget* target,
+ bool antiAlias) {
if (!target->getCaps().fShaderDerivativeSupport || !antiAlias ||
kHairLine_PathFill == fill || GrIsFillInverted(fill) ||
- !path.isConvex()) {
+ !pathIsConvex) {
return false;
} else {
return true;
}
}
+bool GrAAConvexPathRenderer::canDrawPath(const SkPath& path,
+ GrPathFill fill,
+ const GrDrawTarget* target,
+ bool antiAlias) const {
+ return staticCanDrawPath(path.isConvex(), fill, target, antiAlias);
+}
+
bool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath,
GrPathFill fill,
const GrVec* translate,
diff --git a/src/gpu/GrAAConvexPathRenderer.h b/src/gpu/GrAAConvexPathRenderer.h
index df0c00126a..875560c1ef 100644
--- a/src/gpu/GrAAConvexPathRenderer.h
+++ b/src/gpu/GrAAConvexPathRenderer.h
@@ -17,6 +17,12 @@ public:
GrPathFill fill,
const GrDrawTarget* target,
bool antiAlias) const SK_OVERRIDE;
+
+ static bool staticCanDrawPath(bool pathIsConvex,
+ GrPathFill fill,
+ const GrDrawTarget* target,
+ bool antiAlias);
+
protected:
virtual bool onDrawPath(const SkPath& path,
GrPathFill fill,
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index 701bf3a08d..94d94a378a 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -574,10 +574,10 @@ bool GrAAHairLinePathRenderer::createGeom(
return true;
}
-bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path,
- GrPathFill fill,
- const GrDrawTarget* target,
- bool antiAlias) const {
+bool GrAAHairLinePathRenderer::staticCanDrawPath(const SkPath& path,
+ GrPathFill fill,
+ const GrDrawTarget* target,
+ bool antiAlias) {
if (fill != kHairLine_PathFill || !antiAlias) {
return false;
}
@@ -591,6 +591,13 @@ bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path,
return true;
}
+bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path,
+ GrPathFill fill,
+ const GrDrawTarget* target,
+ bool antiAlias) const {
+ return staticCanDrawPath(path, fill, target, antiAlias);
+}
+
bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
GrPathFill fill,
const GrVec* translate,
diff --git a/src/gpu/GrAAHairLinePathRenderer.h b/src/gpu/GrAAHairLinePathRenderer.h
index 6dd9ea9f98..e45fa351fb 100644
--- a/src/gpu/GrAAHairLinePathRenderer.h
+++ b/src/gpu/GrAAHairLinePathRenderer.h
@@ -21,6 +21,12 @@ public:
GrPathFill fill,
const GrDrawTarget* target,
bool antiAlias) const SK_OVERRIDE;
+
+ static bool staticCanDrawPath(const SkPath& path,
+ GrPathFill fill,
+ const GrDrawTarget* target,
+ bool antiAlias);
+
protected:
virtual bool onDrawPath(const SkPath& path,
GrPathFill fill,
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index f8e81a3b80..e618bf17f0 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -13,6 +13,11 @@
#include "GrPathRenderer.h"
#include "GrPaint.h"
#include "SkRasterClip.h"
+#include "GrAAConvexPathRenderer.h"
+#include "GrAAHairLinePathRenderer.h"
+
+// TODO: move GrSWMaskHelper out of GrSoftwarePathRender.h & remove this include
+#include "GrSoftwarePathRenderer.h"
//#define GR_AA_CLIP 1
//#define GR_SW_CLIP 1
@@ -55,12 +60,80 @@ void setup_drawstate_aaclip(GrGpu* gpu,
GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(maskStage));
}
-bool create_mask_in_sw() {
- return false;
}
+/*
+ * This method traverses the clip stack to see if the GrSoftwarePathRenderer
+ * will be used on any element. If so, it returns true to indicate that the
+ * entire clip should be rendered in SW and then uploaded en masse to the gpu.
+ */
+bool GrClipMaskManager::useSWOnlyPath(GrGpu* gpu, const GrClip& clipIn) {
+ // TODO: this check is correct for the createAlphaClipMask path.
+ // The createStencilClipMask path does a lot more flip flopping of fill,
+ // etc - so this isn't quite correct in that case
+
+ // TODO: generalize this test so that when
+ // a clip gets complex enough it can just be done in SW regardless
+ // of whether it would invoke the GrSoftwarePathRenderer.
+ bool useSW = false;
+
+ for (int i = 0; i < clipIn.getElementCount(); ++i) {
+
+ if (SkRegion::kReplace_Op == clipIn.getOp(i)) {
+ // Everything before a replace op can be ignored so start
+ // afresh w.r.t. determining if any element uses the SW path
+ useSW = false;
+ }
+
+ if (!clipIn.getDoAA(i)) {
+ // non-anti-aliased rects and paths can always be drawn either
+ // directly or by the GrDefaultPathRenderer
+ continue;
+ }
+
+ if (kRect_ClipType == clipIn.getElementType(i)) {
+ // Antialiased rects are converted to paths and then drawn with
+ // kEvenOdd_PathFill.
+ if (!GrAAConvexPathRenderer::staticCanDrawPath(
+ true, // always convex
+ kEvenOdd_PathFill,
+ gpu, true)) {
+ // if the GrAAConvexPathRenderer can't render this rect (due
+ // to lack of derivative support in the shaders) then
+ // the GrSoftwarePathRenderer will be used
+ useSW = true;
+ }
+
+ continue;
+ }
+
+ // only paths need to be considered in the rest of the loop body
+
+ if (GrAAHairLinePathRenderer::staticCanDrawPath(clipIn.getPath(i),
+ clipIn.getPathFill(i),
+ gpu,
+ clipIn.getDoAA(i))) {
+ // the hair line path renderer can handle this one
+ continue;
+ }
+
+ if (GrAAConvexPathRenderer::staticCanDrawPath(
+ clipIn.getPath(i).isConvex(),
+ clipIn.getPathFill(i),
+ gpu,
+ clipIn.getDoAA(i))) {
+ // the convex path renderer can handle this one
+ continue;
+ }
+
+ // otherwise the GrSoftwarePathRenderer is going to be invoked
+ useSW = true;
+ }
+
+ return useSW;
}
+
////////////////////////////////////////////////////////////////////////////////
// sort out what kind of clip mask needs to be created: alpha, stencil,
// scissor, or entirely software
@@ -85,7 +158,7 @@ bool GrClipMaskManager::createClipMask(GrGpu* gpu,
GrAssert(NULL != rt);
#if GR_SW_CLIP
- if (create_mask_in_sw()) {
+ if (useSWOnlyPath(gpu, clipIn)) {
// The clip geometry is complex enough that it will be more
// efficient to create it entirely in software
GrTexture* result = NULL;
@@ -133,7 +206,7 @@ bool GrClipMaskManager::createClipMask(GrGpu* gpu,
GrRect bounds;
GrRect rtRect;
rtRect.setLTRB(0, 0,
- GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
+ GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
if (clipIn.hasConservativeBounds()) {
bounds = clipIn.getConservativeBounds();
if (!bounds.intersect(rtRect)) {
@@ -786,6 +859,27 @@ bool GrClipMaskManager::createStencilClipMask(GrGpu* gpu,
return true;
}
+namespace {
+
+GrPathFill invert_fill(GrPathFill fill) {
+ static const GrPathFill gInvertedFillTable[] = {
+ kInverseWinding_PathFill, // kWinding_PathFill
+ kInverseEvenOdd_PathFill, // kEvenOdd_PathFill
+ kWinding_PathFill, // kInverseWinding_PathFill
+ kEvenOdd_PathFill, // kInverseEvenOdd_PathFill
+ kHairLine_PathFill, // kHairLine_PathFill
+ };
+ GR_STATIC_ASSERT(0 == kWinding_PathFill);
+ GR_STATIC_ASSERT(1 == kEvenOdd_PathFill);
+ GR_STATIC_ASSERT(2 == kInverseWinding_PathFill);
+ GR_STATIC_ASSERT(3 == kInverseEvenOdd_PathFill);
+ GR_STATIC_ASSERT(4 == kHairLine_PathFill);
+ GR_STATIC_ASSERT(5 == kPathFillCount);
+ return gInvertedFillTable[fill];
+}
+
+}
+
////////////////////////////////////////////////////////////////////////////////
bool GrClipMaskManager::createSoftwareClipMask(GrGpu* gpu,
const GrClip& clipIn,
@@ -803,30 +897,98 @@ bool GrClipMaskManager::createSoftwareClipMask(GrGpu* gpu,
return false;
}
-#if 0
- SkRasterClip rasterClip;
+ GrSWMaskHelper helper(fAACache.getContext());
- // TODO: refactor GrClip out of existance and use SkCanvas's ClipVisitor
- // - may have to move it to SkClipStack
- for (int i = 0; i < clipIn.getElementCount(); ++i) {
+ helper.init(*resultBounds, NULL, false);
+
+ int count = clipIn.getElementCount();
+
+ bool clearToInside;
+ SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning
+ int start = process_initial_clip_elements(clipIn,
+ *resultBounds,
+ &clearToInside,
+ &startOp);
+
+ helper.clear(clearToInside ? SK_ColorWHITE : 0x00000000);
+
+ for (int i = start; i < count; ++i) {
+
+ SkRegion::Op op = (i == start) ? startOp : clipIn.getOp(i);
+
+ if (SkRegion::kIntersect_Op == op ||
+ SkRegion::kReverseDifference_Op == op) {
+ // Intersect and reverse difference require modifying pixels
+ // outside of the geometry that is being "drawn". In both cases
+ // we erase all the pixels outside of the geometry but
+ // leave the pixels inside the geometry alone. For reverse
+ // difference we invert all the pixels before clearing the ones
+ // outside the geometry.
+ if (SkRegion::kReverseDifference_Op == op) {
+ SkRect temp = SkRect::MakeLTRB(
+ SkIntToScalar(resultBounds->left()),
+ SkIntToScalar(resultBounds->top()),
+ SkIntToScalar(resultBounds->right()),
+ SkIntToScalar(resultBounds->bottom()));
+
+ // invert the entire scene
+ helper.draw(temp, SkRegion::kXOR_Op, false, SK_ColorWHITE);
+ }
+
+ if (kRect_ClipType == clipIn.getElementType(i)) {
+
+ // convert the rect to a path so we can invert the fill
+ SkPath temp;
+ temp.addRect(clipIn.getRect(i));
+
+ helper.draw(temp, SkRegion::kReplace_Op,
+ kInverseEvenOdd_PathFill, clipIn.getDoAA(i),
+ 0x00000000);
+ } else {
+ GrAssert(kPath_ClipType == clipIn.getElementType(i));
+
+ helper.draw(clipIn.getPath(i),
+ SkRegion::kReplace_Op,
+ invert_fill(clipIn.getPathFill(i)),
+ clipIn.getDoAA(i),
+ 0x00000000);
+ }
+
+ continue;
+ }
+
+ // The other ops (union, xor, diff) only affect pixels inside
+ // the geometry so they can just be drawn normally
if (kRect_ClipType == clipIn.getElementType(i)) {
- rasterClip.op(clipIn.getRect(i), clipIn.getOp(i), clipIn.getDoAA(i));
+
+ helper.draw(clipIn.getRect(i),
+ op,
+ clipIn.getDoAA(i), SK_ColorWHITE);
+
} else {
GrAssert(kPath_ClipType == clipIn.getElementType(i));
- SkIPoint deviceSize = SkIPoint::Make(resultBounds->width(),
- resultBounds->height());
-
- SkRasterClip::clipPathHelper(&rasterClip,
- clipIn.getPath(i),
- clipIn.getOp(i),
- clipIn.getDoAA(i),
- deviceSize);
+ helper.draw(clipIn.getPath(i),
+ op,
+ clipIn.getPathFill(i),
+ clipIn.getDoAA(i), SK_ColorWHITE);
}
}
- // TODO: need to get pixels out of SkRasterClip & into the texture!
-#endif
+ // Because we are using the scratch texture cache, "accum" may be
+ // larger than expected and have some cruft in the areas we aren't using.
+ // Clear it out.
+
+ // TODO: need a simpler way to clear the texture - can we combine
+ // the clear and the writePixels (inside toTexture)
+ GrDrawState* drawState = gpu->drawState();
+ GrAssert(NULL != drawState);
+ GrRenderTarget* temp = drawState->getRenderTarget();
+ clear(gpu, accum, 0x00000000);
+ // can't leave the accum bound as a rendertarget
+ drawState->setRenderTarget(temp);
+
+ helper.toTexture(accum);
*result = accum;
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index 02fc875f83..d5fcc831aa 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -332,6 +332,8 @@ private:
GrTexture** result,
GrIRect *resultBounds);
+ bool useSWOnlyPath(GrGpu* gpu, const GrClip& clipIn);
+
bool drawPath(GrGpu* gpu,
const SkPath& path,
GrPathFill fill,
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index 410223cd62..817f55a86d 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -101,7 +101,7 @@ bool get_path_and_clip_bounds(const GrDrawTarget* target,
SkXfermode::Mode op_to_mode(SkRegion::Op op) {
static const SkXfermode::Mode modeMap[] = {
- SkXfermode::kSrcOut_Mode, // kDifference_Op
+ SkXfermode::kDstOut_Mode, // kDifference_Op
SkXfermode::kMultiply_Mode, // kIntersect_Op
SkXfermode::kSrcOver_Mode, // kUnion_Op
SkXfermode::kXor_Mode, // kXOR_Op
@@ -118,14 +118,14 @@ SkXfermode::Mode op_to_mode(SkRegion::Op op) {
* Draw a single rect element of the clip stack into the accumulation bitmap
*/
void GrSWMaskHelper::draw(const GrRect& clientRect, SkRegion::Op op,
- bool antiAlias) {
+ bool antiAlias, GrColor color) {
SkPaint paint;
SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
paint.setXfermode(mode);
paint.setAntiAlias(antiAlias);
- paint.setColor(SK_ColorWHITE);
+ paint.setColor(color);
fDraw.drawRect(clientRect, paint);
@@ -136,7 +136,7 @@ void GrSWMaskHelper::draw(const GrRect& clientRect, SkRegion::Op op,
* Draw a single path element of the clip stack into the accumulation bitmap
*/
void GrSWMaskHelper::draw(const SkPath& clientPath, SkRegion::Op op,
- GrPathFill fill, bool antiAlias) {
+ GrPathFill fill, bool antiAlias, GrColor color) {
SkPaint paint;
SkPath tmpPath;
@@ -157,23 +157,30 @@ void GrSWMaskHelper::draw(const SkPath& clientPath, SkRegion::Op op,
paint.setXfermode(mode);
paint.setAntiAlias(antiAlias);
- paint.setColor(SK_ColorWHITE);
+ paint.setColor(color);
fDraw.drawPath(*pathToDraw, paint);
SkSafeUnref(mode);
}
-bool GrSWMaskHelper::init(const GrIRect& pathDevBounds, const GrPoint* translate) {
- fMatrix = fContext->getMatrix();
+bool GrSWMaskHelper::init(const GrIRect& pathDevBounds,
+ const GrPoint* translate,
+ bool useMatrix) {
+ if (useMatrix) {
+ fMatrix = fContext->getMatrix();
+ } else {
+ fMatrix.setIdentity();
+ }
+
if (NULL != translate) {
fMatrix.postTranslate(translate->fX, translate->fY);
}
fMatrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
- -pathDevBounds.fTop * SK_Scalar1);
+ -pathDevBounds.fTop * SK_Scalar1);
GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
- pathDevBounds.height());
+ pathDevBounds.height());
fBM.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
if (!fBM.allocPixels()) {
@@ -237,11 +244,12 @@ bool sw_draw_path_to_mask_texture(const SkPath& clientPath,
bool antiAlias) {
GrSWMaskHelper helper(context);
- if (!helper.init(pathDevBounds, translate)) {
+ if (!helper.init(pathDevBounds, translate, true)) {
return false;
}
- helper.draw(clientPath, SkRegion::kReplace_Op, fill, antiAlias);
+ helper.draw(clientPath, SkRegion::kReplace_Op,
+ fill, antiAlias, SK_ColorWHITE);
if (!helper.getTexture(tex)) {
return false;
@@ -339,4 +347,3 @@ bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path,
return false;
}
-
diff --git a/src/gpu/GrSoftwarePathRenderer.h b/src/gpu/GrSoftwarePathRenderer.h
index 4b75d036f3..74715f6812 100644
--- a/src/gpu/GrSoftwarePathRenderer.h
+++ b/src/gpu/GrSoftwarePathRenderer.h
@@ -28,17 +28,24 @@ public:
}
- void draw(const GrRect& clientRect, SkRegion::Op op, bool antiAlias);
+ void draw(const GrRect& clientRect, SkRegion::Op op,
+ bool antiAlias, GrColor color);
void draw(const SkPath& clientPath, SkRegion::Op op,
- GrPathFill fill, bool antiAlias);
+ GrPathFill fill, bool antiAlias, GrColor color);
- bool init(const GrIRect& pathDevBounds, const GrPoint* translate);
+ bool init(const GrIRect& pathDevBounds,
+ const GrPoint* translate,
+ bool useMatrix);
bool getTexture(GrAutoScratchTexture* tex);
void toTexture(GrTexture* texture);
+ void clear(GrColor color) {
+ fBM.eraseColor(color);
+ }
+
protected:
private:
GrContext* fContext;