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:
parent
5acc0e36d9
commit
fa66294c77
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user