Fix inverse union complex clip stencil rules, skip screen filling rectangles
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 9 Dec 2011 21:23:46 +0000 (21:23 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 9 Dec 2011 21:23:46 +0000 (21:23 +0000)
Review URL: http://codereview.appspot.com/5480054/

git-svn-id: http://skia.googlecode.com/svn/trunk@2848 2bbb7eff-a529-9590-31e7-b0007b416f81

src/gpu/GrGpu.cpp
src/gpu/GrStencil.cpp

index eb96c57..a949acd 100644 (file)
@@ -446,6 +446,7 @@ namespace {
 // whether the initial clear should be to the inside- or outside-the-clip value,
 // and what op should be used to draw the first element that isn't skipped.
 int process_initial_clip_elements(const GrClip& clip,
+                                  const GrRect& bounds,
                                   bool* clearToInside,
                                   GrSetOp* startOp) {
 
@@ -468,6 +469,12 @@ int process_initial_clip_elements(const GrClip& clip,
                 done = true;
                 break;
             case kIntersect_SetOp:
+                // if this element contains the entire bounds then we
+                // can skip it.
+                if (kRect_ClipType == clip.getElementType(curr)
+                    && clip.getRect(curr).contains(bounds)) {
+                    break;
+                }
                 // if everything is initially clearToInside then intersect is
                 // same as clear to 0 and treat as a replace. Otherwise,
                 // set stays empty.
@@ -595,7 +602,9 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
             
             bool clearToInside;
             GrSetOp startOp = kReplace_SetOp; // suppress warning
-            int start = process_initial_clip_elements(clip, &clearToInside,
+            int start = process_initial_clip_elements(clip,
+                                                      rtRect,
+                                                      &clearToInside,
                                                       &startOp);
 
             this->clearStencilClip(clipRect, clearToInside);
@@ -621,6 +630,12 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
                     canRenderDirectToStencil = true;
                     fill = kEvenOdd_PathFill;
                     fillInverted = false;
+                    // there is no point in intersecting a screen filling
+                    // rectangle.
+                    if (kIntersect_SetOp == clip.getOp(c) &&
+                        clip.getRect(c).contains(rtRect)) {
+                        continue;
+                    }
                 } else {
                     fill = clip.getPathFill(c);
                     fillInverted = GrIsFillInverted(fill);
index a66fbfd..81b3b8d 100644 (file)
@@ -110,26 +110,25 @@ static const GrStencilSettings gUserToClipUnionPass1 = {
     0xffff,              0xffff
 };
 
-// for inverse first pass finds non-zerp user with clip bit set
-// and converts it to just clip bit set
+// first pass finds zeros in the user bits and if found sets
+// the clip bit to 1
 static const GrStencilSettings gInvUserToClipUnionPass0 = {
     kReplace_StencilOp,  kReplace_StencilOp,
     kKeep_StencilOp,     kKeep_StencilOp,
-    kLess_StencilFunc,   kLess_StencilFunc,
-    0xffff,              0xffff,
+    kEqual_StencilFunc,  kEqual_StencilFunc,
+    0xffff,              0xffff,           // unset clip bit
     0x0000,              0x0000,           // set clip bit
-    0xffff,              0xffff
+    0x0000,              0x0000            // set clip bit
 };
 
-// second pass lets anything through with a nonzero user portion
-// and writes a ref value with just the clip bit set to it.
+// second pass zeros the user bits
 static const GrStencilSettings gInvUserToClipUnionPass1 = {
-    kReplace_StencilOp,  kReplace_StencilOp,
+    kZero_StencilOp,     kZero_StencilOp,
     kZero_StencilOp,     kZero_StencilOp,
     kLess_StencilFunc,   kLess_StencilFunc,
-    0xffff,              0xffff,           // unset clip bit
-    0x0000,              0x0000,           // set clip bit
-    0xffff,              0xffff
+    0xffff,              0xffff,
+    0x0000,              0x0000,
+    0xffff,              0xffff            // unset clip bit
 };
 
 ///////
@@ -301,14 +300,16 @@ bool GrStencilSettings::GetClipPasses(GrSetOp op,
             *numPasses = 2;
             if (invertedFill) {
                 settings[0] = gInvUserToClipUnionPass0;
+                settings[0].fFrontFuncMask &= ~stencilClipMask;
+                settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
                 settings[0].fFrontFuncRef |= stencilClipMask;
-                settings[0].fBackFuncRef = settings[0].fFrontFuncMask;
+                settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+                settings[0].fFrontWriteMask |= stencilClipMask;
+                settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
 
                 settings[1] = gInvUserToClipUnionPass1;
-                settings[1].fFrontFuncMask &= ~stencilClipMask;
-                settings[1].fFrontFuncRef |= stencilClipMask;
-                settings[1].fBackFuncMask = settings[1].fFrontFuncMask;
-                settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+                settings[1].fFrontWriteMask &= ~stencilClipMask;
+                settings[1].fBackWriteMask &= settings[1].fFrontWriteMask;
 
             } else {
                 settings[0] = gUserToClipUnionPass0;