First functioning version of SW-only clip mask creator

http://codereview.appspot.com/6208072/



git-svn-id: http://skia.googlecode.com/svn/trunk@3984 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
robertphillips@google.com 2012-05-17 12:20:22 +00:00
parent 5acc0e36d9
commit fa66294c77
8 changed files with 248 additions and 44 deletions

View File

@ -430,19 +430,26 @@ void create_vertices(const SegmentArray& segments,
}
bool GrAAConvexPathRenderer::canDrawPath(const SkPath& path,
bool GrAAConvexPathRenderer::staticCanDrawPath(bool pathIsConvex,
GrPathFill fill,
const GrDrawTarget* target,
bool antiAlias) const {
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,

View File

@ -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,

View File

@ -574,10 +574,10 @@ bool GrAAHairLinePathRenderer::createGeom(
return true;
}
bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path,
bool GrAAHairLinePathRenderer::staticCanDrawPath(const SkPath& path,
GrPathFill fill,
const GrDrawTarget* target,
bool antiAlias) const {
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,

View File

@ -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,

View File

@ -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;
@ -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());
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);
}
// 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) {
if (kRect_ClipType == clipIn.getElementType(i)) {
rasterClip.op(clipIn.getRect(i), clipIn.getOp(i), clipIn.getDoAA(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));
SkIPoint deviceSize = SkIPoint::Make(resultBounds->width(),
resultBounds->height());
SkRasterClip::clipPathHelper(&rasterClip,
clipIn.getPath(i),
clipIn.getOp(i),
helper.draw(clipIn.getPath(i),
SkRegion::kReplace_Op,
invert_fill(clipIn.getPathFill(i)),
clipIn.getDoAA(i),
deviceSize);
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)) {
helper.draw(clipIn.getRect(i),
op,
clipIn.getDoAA(i), SK_ColorWHITE);
} else {
GrAssert(kPath_ClipType == clipIn.getElementType(i));
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;

View File

@ -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,

View File

@ -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,15 +157,22 @@ 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) {
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);
}
@ -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;
}

View File

@ -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;