diff options
Diffstat (limited to 'src/gpu/GrClipMaskManager.cpp')
-rw-r--r-- | src/gpu/GrClipMaskManager.cpp | 202 |
1 files changed, 182 insertions, 20 deletions
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; |