GrClipMaskManager.cpp revision b0a8a377f832c59cee939ad721e1f87d378b7142
11e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
21e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com/*
31e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com * Copyright 2012 Google Inc.
41e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com *
51e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com * Use of this source code is governed by a BSD-style license that can be
61e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com * found in the LICENSE file.
71e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com */
81e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
91e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrClipMaskManager.h"
10c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrAAConvexPathRenderer.h"
11c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrAAHairLinePathRenderer.h"
12bfe2b9d3a290d0153b82617cd6b65a4814fe89e3jvanverth@google.com#include "GrAARectRenderer.h"
13c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrDrawTargetCaps.h"
141e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrGpu.h"
15c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrPaint.h"
16c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrPathRenderer.h"
171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrRenderTarget.h"
181e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrStencilBuffer.h"
19c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrSWMaskHelper.h"
20907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org#include "effects/GrTextureDomain.h"
2165ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org#include "effects/GrConvexPolyEffect.h"
22c2f7824436d05da6e8514d06a54773538aace028commit-bot@chromium.org#include "effects/GrRRectEffect.h"
236b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com#include "SkRasterClip.h"
245f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com#include "SkStrokeRec.h"
25c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com#include "SkTLazy.h"
26c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com
27ba998f2ddc5a904376bfdb118976868b9ee2b6e8robertphillips@google.com#define GR_AA_CLIP 1
28a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
298182fa0cac76e7e6d583aebba060229230516887bsalomon@google.comtypedef SkClipStack::Element Element;
3051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
314c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.comusing namespace GrReducedClip;
324c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
3351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com////////////////////////////////////////////////////////////////////////////////
34e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.comnamespace {
35fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// set up the draw state to enable the aa clipping mask. Besides setting up the
3608283afc265f1153834256fc1012519813ba6b73bsalomon@google.com// stage matrix this also alters the vertex layout
37e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.comvoid setup_drawstate_aaclip(GrGpu* gpu,
38e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                            GrTexture* result,
39e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                            const SkIRect &devBound) {
40a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    GrDrawState* drawState = gpu->drawState();
41f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(drawState);
42a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
43b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com    SkMatrix mat;
44c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    // We want to use device coords to compute the texture coordinates. We set our matrix to be
45c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    // equal to the view matrix followed by an offset to the devBound, and then a scaling matrix to
46c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    // normalized coords. We apply this matrix to the vertex positions rather than local coords.
47a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    mat.setIDiv(result->width(), result->height());
48fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    mat.preTranslate(SkIntToScalar(-devBound.fLeft),
497b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                     SkIntToScalar(-devBound.fTop));
50a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    mat.preConcat(drawState->getViewMatrix());
51a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
527b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height());
534c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // This could be a long-lived effect that is cached with the alpha-mask.
54b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    drawState->addCoverageProcessor(
55eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com        GrTextureDomainEffect::Create(result,
567b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                      mat,
57907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org                                      GrTextureDomain::MakeTexelDomain(result, domainTexels),
58907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org                                      GrTextureDomain::kDecal_Mode,
59b86add1ad37776818e1f730359ec587c9fdbff5fhumper@google.com                                      GrTextureParams::kNone_FilterMode,
6077af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                                      kPosition_GrCoordSet))->unref();
61a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com}
62a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
63e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.combool path_needs_SW_renderer(GrContext* context,
64e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                            GrGpu* gpu,
65e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                            const SkPath& origPath,
66e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                            const SkStrokeRec& stroke,
67e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                            bool doAA) {
68e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    // the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer
69e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    SkTCopyOnFirstWrite<SkPath> path(origPath);
70e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    if (path->isInverseFillType()) {
71e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com        path.writable()->toggleInverseFillType();
72e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    }
73e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    // last (false) parameter disallows use of the SW path renderer
7445a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com    GrPathRendererChain::DrawType type = doAA ?
7545a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                         GrPathRendererChain::kColorAntiAlias_DrawType :
7645a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                         GrPathRendererChain::kColor_DrawType;
7745a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com
78e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    return NULL == context->getPathRenderer(*path, stroke, gpu, false, type);
79e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com}
80e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com
816b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com}
826b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
83fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com/*
84fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * This method traverses the clip stack to see if the GrSoftwarePathRenderer
85fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * will be used on any element. If so, it returns true to indicate that the
86fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * entire clip should be rendered in SW and then uploaded en masse to the gpu.
87fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com */
884c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.combool GrClipMaskManager::useSWOnlyPath(const ElementList& elements) {
89a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com
908a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com    // TODO: generalize this function so that when
91fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // a clip gets complex enough it can just be done in SW regardless
92fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // of whether it would invoke the GrSoftwarePathRenderer.
935f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
94d21444aab7128c97f4e0eb5e9bf05111d5037292skia.committer@gmail.com
954c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    for (ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) {
964c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        const Element* element = iter.get();
97f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com        // rects can always be drawn directly w/o using the software path
98e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        // Skip rrects once we're drawing them directly.
99e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        if (Element::kRect_Type != element->getType()) {
100e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            SkPath path;
101e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            element->asPath(&path);
102e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            if (path_needs_SW_renderer(this->getContext(), fGpu, path, stroke, element->isAA())) {
103e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                return true;
104e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            }
105fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        }
106fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    }
1074c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    return false;
108a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com}
109a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
110e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.orgbool GrClipMaskManager::installClipEffects(const ElementList& elements,
111e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                                           GrDrawState::AutoRestoreEffects* are,
112e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                                           const SkVector& clipToRTOffset,
113217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein                                           const SkRect* drawBounds) {
114e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
115e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    GrDrawState* drawState = fGpu->drawState();
116e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    SkRect boundsInClipSpace;
11749f085dddff10473b6ebf832a974288300224e60bsalomon    if (drawBounds) {
118e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        boundsInClipSpace = *drawBounds;
119e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY);
120e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    }
121e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
122e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    are->set(drawState);
123e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    GrRenderTarget* rt = drawState->getRenderTarget();
124217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein    ElementList::Iter iter(elements);
125e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
126e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    bool setARE = false;
127e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    bool failed = false;
128e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
12949f085dddff10473b6ebf832a974288300224e60bsalomon    while (iter.get()) {
130e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        SkRegion::Op op = iter.get()->getOp();
131e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        bool invert;
132e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        bool skip = false;
133e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        switch (op) {
134e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            case SkRegion::kReplace_Op:
135e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                SkASSERT(iter.get() == elements.head());
136e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                // Fallthrough, handled same as intersect.
137e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            case SkRegion::kIntersect_Op:
138e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                invert = false;
13949f085dddff10473b6ebf832a974288300224e60bsalomon                if (drawBounds && iter.get()->contains(boundsInClipSpace)) {
140e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    skip = true;
141e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                }
142e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                break;
143e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            case SkRegion::kDifference_Op:
144e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                invert = true;
145e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                // We don't currently have a cheap test for whether a rect is fully outside an
146e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                // element's primitive, so don't attempt to set skip.
147e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                break;
148e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            default:
149e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                failed = true;
150e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                break;
151e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        }
152e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        if (failed) {
153e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            break;
154e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        }
155e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
156e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        if (!skip) {
157b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt            GrPrimitiveEdgeType edgeType;
158e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            if (GR_AA_CLIP && iter.get()->isAA()) {
159e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                if (rt->isMultisampled()) {
160217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein                    // Coverage based AA clips don't place nicely with MSAA.
161e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    failed = true;
162e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    break;
163e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                }
164b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                edgeType =
165b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                        invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProcessorEdgeType;
166e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            } else {
167b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                edgeType =
168b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                        invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProcessorEdgeType;
169e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            }
170b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt            SkAutoTUnref<GrFragmentProcessor> fp;
171e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            switch (iter.get()->getType()) {
172e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                case SkClipStack::Element::kPath_Type:
173b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                    fp.reset(GrConvexPolyEffect::Create(edgeType, iter.get()->getPath(),
174e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                        &clipToRTOffset));
175e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    break;
176e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                case SkClipStack::Element::kRRect_Type: {
177e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    SkRRect rrect = iter.get()->getRRect();
178e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY);
179b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                    fp.reset(GrRRectEffect::Create(edgeType, rrect));
180e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    break;
181e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                }
182e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                case SkClipStack::Element::kRect_Type: {
183e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    SkRect rect = iter.get()->getRect();
184e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    rect.offset(clipToRTOffset.fX, clipToRTOffset.fY);
185b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                    fp.reset(GrConvexPolyEffect::Create(edgeType, rect));
186e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    break;
187e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                }
188e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                default:
189e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    break;
190e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            }
191b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt            if (fp) {
192e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                if (!setARE) {
193e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    are->set(fGpu->drawState());
194e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                    setARE = true;
195e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                }
196b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                fGpu->drawState()->addCoverageProcessor(fp);
197217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein            } else {
198e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                failed = true;
199e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                break;
200e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            }
201e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        }
202217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein        iter.next();
203e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    }
204e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
205e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    if (failed) {
206e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        are->set(NULL);
207e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    }
208e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
209e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    return !failed;
210e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org}
211e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
212f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
2136b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// sort out what kind of clip mask needs to be created: alpha, stencil,
2146b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// scissor, or entirely software
215eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.combool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn,
2163ae0e6c2b213d45c370846a4d4182a6754ca493ecommit-bot@chromium.org                                      GrDrawState::AutoRestoreEffects* are,
2173ae0e6c2b213d45c370846a4d4182a6754ca493ecommit-bot@chromium.org                                      const SkRect* devBounds) {
218c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    fCurrClipMaskType = kNone_ClipMaskType;
219a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
2204c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    ElementList elements(16);
221d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    int32_t genID;
2224c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    InitialState initialState;
2234c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    SkIRect clipSpaceIBounds;
2244c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    bool requiresAA;
2254c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
22613b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
2271e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2284c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    const GrRenderTarget* rt = drawState->getRenderTarget();
2291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // GrDrawTarget should have filtered this for us
23049f085dddff10473b6ebf832a974288300224e60bsalomon    SkASSERT(rt);
2311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2324c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    bool ignoreClip = !drawState->isClipState() || clipDataIn->fClipStack->isWideOpen();
2334c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
2344c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (!ignoreClip) {
2354c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height());
2364c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        clipSpaceRTIBounds.offset(clipDataIn->fOrigin);
2374c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        ReduceClipStack(*clipDataIn->fClipStack,
2384c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                        clipSpaceRTIBounds,
2394c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                        &elements,
240d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                        &genID,
2414c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                        &initialState,
2424c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                        &clipSpaceIBounds,
2434c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                        &requiresAA);
2444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        if (elements.isEmpty()) {
2454c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            if (kAllIn_InitialState == initialState) {
2464c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                ignoreClip = clipSpaceIBounds == clipSpaceRTIBounds;
2474c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            } else {
2484c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                return false;
2494c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            }
2504c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        }
2514c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    }
2523e11c0bd92fbd12f59080c3f9450201d6105db83robertphillips@google.com
2534c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (ignoreClip) {
2544c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        fGpu->disableScissor();
2554c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        this->setGpuStencil();
2564c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        return true;
257a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
258a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
259e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // An element count of 4 was chosen because of the common pattern in Blink of:
260e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    //   isect RR
261e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    //   diff  RR
262e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    //   isect convex_poly
263e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    //   isect convex_poly
264e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // when drawing rounded div borders. This could probably be tuned based on a
265e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // configuration's relative costs of switching RTs to generate a mask vs
266e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // longer shaders.
267e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    if (elements.count() <= 4) {
268e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        SkVector clipToRTOffset = { SkIntToScalar(-clipDataIn->fOrigin.fX),
269b21fac156d9287d6c0cfd446d707c4c7be6fae6ecommit-bot@chromium.org                                    SkIntToScalar(-clipDataIn->fOrigin.fY) };
270e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        if (elements.isEmpty() ||
271217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein            (requiresAA && this->installClipEffects(elements, are, clipToRTOffset, devBounds))) {
272217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein            SkIRect scissorSpaceIBounds(clipSpaceIBounds);
273217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein            scissorSpaceIBounds.offset(-clipDataIn->fOrigin);
274217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein            if (NULL == devBounds ||
275217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein                !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) {
276217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein                fGpu->enableScissor(scissorSpaceIBounds);
277e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            } else {
278217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein                fGpu->disableScissor();
279e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            }
28065ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org            this->setGpuStencil();
28165ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org            return true;
28265ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org        }
28365ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org    }
284d3066bd9b4a37cf4a39e7df7e1432f3df10dbc67bsalomon@google.com
28565ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org#if GR_AA_CLIP
286a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    // If MSAA is enabled we can do everything in the stencil buffer.
2874c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (0 == rt->numSamples() && requiresAA) {
2886b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        GrTexture* result = NULL;
289a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com
2904c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        if (this->useSWOnlyPath(elements)) {
2914c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // The clip geometry is complex enough that it will be more efficient to create it
2924c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // entirely in software
2934c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            result = this->createSoftwareClipMask(genID,
2944c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                  initialState,
2954c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                  elements,
2964c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                  clipSpaceIBounds);
2974c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        } else {
2984c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            result = this->createAlphaClipMask(genID,
2994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                               initialState,
3004c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                               elements,
3014c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                               clipSpaceIBounds);
3024c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        }
3036b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
30449f085dddff10473b6ebf832a974288300224e60bsalomon        if (result) {
3054c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // The mask's top left coord should be pinned to the rounded-out top left corner of
3064c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // clipSpace bounds. We determine the mask's position WRT to the render target here.
3074c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            SkIRect rtSpaceMaskBounds = clipSpaceIBounds;
3084c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            rtSpaceMaskBounds.offset(-clipDataIn->fOrigin);
309eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com            are->set(fGpu->drawState());
3104c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            setup_drawstate_aaclip(fGpu, result, rtSpaceMaskBounds);
311a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            fGpu->disableScissor();
312a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            this->setGpuStencil();
313f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            return true;
314f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        }
3154c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        // if alpha clip mask creation fails fall through to the non-AA code paths
316f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
317f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com#endif // GR_AA_CLIP
318f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
3194c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // Either a hard (stencil buffer) clip was explicitly requested or an anti-aliased clip couldn't
3204c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // be created. In either case, free up the texture in the anti-aliased mask cache.
3214c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // TODO: this may require more investigation. Ganesh performs a lot of utility draws (e.g.,
3224c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // clears, InOrderDrawBuffer playbacks) that hit the stencil buffer path. These may be
3234c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // "incorrectly" clearing the AA cache.
3245acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    fAACache.reset();
3255acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com
3261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // use the stencil clip if we can't represent the clip as a rectangle.
3274c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    SkIPoint clipSpaceToStencilSpaceOffset = -clipDataIn->fOrigin;
328d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    this->createStencilClipMask(genID,
329d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                                initialState,
3304c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                elements,
3314c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                clipSpaceIBounds,
3324c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                clipSpaceToStencilSpaceOffset);
3334c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
3344c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // This must occur after createStencilClipMask. That function may change the scissor. Also, it
3354c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // only guarantees that the stencil mask is correct within the bounds it was passed, so we must
3364c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // use both stencil and scissor test to the bounds for the final draw.
3374c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    SkIRect scissorSpaceIBounds(clipSpaceIBounds);
3384c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset);
3394c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    fGpu->enableScissor(scissorSpaceIBounds);
340a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    this->setGpuStencil();
3411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    return true;
3421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
3431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
3441e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#define VISUALIZE_COMPLEX_CLIP 0
3451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
3461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#if VISUALIZE_COMPLEX_CLIP
347223137f49d1a4e805f5c1b1c20b7fd68719ac54btfarina@chromium.org    #include "SkRandom.h"
348223137f49d1a4e805f5c1b1c20b7fd68719ac54btfarina@chromium.org    SkRandom gRandom;
3491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    #define SET_RANDOM_COLOR drawState->setColor(0xff000000 | gRandom.nextU());
3501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#else
3511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    #define SET_RANDOM_COLOR
3521e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#endif
3531e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
3541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.comnamespace {
355f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
356f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
357fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// set up the OpenGL blend function to perform the specified
358fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// boolean operation for alpha clip mask creation
3596b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.comvoid setup_boolean_blendcoeffs(GrDrawState* drawState, SkRegion::Op op) {
360f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
361f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    switch (op) {
362f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kReplace_Op:
36347059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
364f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
365f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kIntersect_Op:
36647059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
367f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
368f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kUnion_Op:
36947059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
370f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
371f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kXOR_Op:
37247059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kIDC_GrBlendCoeff, kISC_GrBlendCoeff);
373f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
374f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kDifference_Op:
37547059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
376f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
377f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kReverseDifference_Op:
37847059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kIDC_GrBlendCoeff, kZero_GrBlendCoeff);
379f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
380f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        default:
381f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org            SkASSERT(false);
382f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
383f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
384f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
385f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
38672176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com}
387f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
388f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
389b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.combool GrClipMaskManager::drawElement(GrTexture* target,
390e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                                    const SkClipStack::Element* element,
391e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                                    GrPathRenderer* pr) {
39213b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
393f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
394f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    drawState->setRenderTarget(target->asRenderTarget());
395f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
396e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org    // TODO: Draw rrects directly here.
3978182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    switch (element->getType()) {
398e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        case Element::kEmpty_Type:
399e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            SkDEBUGFAIL("Should never get here with an empty element.");
400e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            break;
4018182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        case Element::kRect_Type:
402b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt            // TODO: Do rects directly to the accumulator using a aa-rect GrProcessor that covers
403b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt            // the entire mask bounds and writes 0 outside the rect.
4048182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            if (element->isAA()) {
405cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com                getContext()->getAARectRenderer()->fillAARect(fGpu,
406cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com                                                              fGpu,
407cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com                                                              element->getRect(),
408b19cb7f36785f3ad3b1512c342fc662ab79e3fcarobertphillips@google.com                                                              SkMatrix::I(),
4099c0822a4150e23cec9f9b72bd1abc2c5f9ea5a3bbsalomon                                                              element->getRect());
4108182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            } else {
41101c8da1eef36570374f7e8764a38b25bf16ab7a6bsalomon                fGpu->drawSimpleRect(element->getRect());
4128182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            }
4138182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            return true;
414e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        default: {
415e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            SkPath path;
416e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            element->asPath(&path);
417e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            if (path.isInverseFillType()) {
418e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                path.toggleInverseFillType();
419e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com            }
4205f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
421e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com            if (NULL == pr) {
422e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                GrPathRendererChain::DrawType type;
423e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_DrawType :
424e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                                         GrPathRendererChain::kColor_DrawType;
425e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                pr = this->getContext()->getPathRenderer(path, stroke, fGpu, false, type);
426e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com            }
427e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com            if (NULL == pr) {
4284c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                return false;
4294c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            }
430e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            pr->drawPath(path, stroke, fGpu, element->isAA());
4314c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            break;
4324c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        }
433f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
434f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    return true;
435f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
436f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
437b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.combool GrClipMaskManager::canStencilAndDrawElement(GrTexture* target,
438b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                                 const SkClipStack::Element* element,
439e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                                                 GrPathRenderer** pr) {
440b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
441b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    drawState->setRenderTarget(target->asRenderTarget());
442b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
443e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org    if (Element::kRect_Type == element->getType()) {
444e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        return true;
445e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org    } else {
446e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        // We shouldn't get here with an empty clip element.
447e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        SkASSERT(Element::kEmpty_Type != element->getType());
448e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        SkPath path;
449e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        element->asPath(&path);
450e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        if (path.isInverseFillType()) {
451e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            path.toggleInverseFillType();
452b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        }
453e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
454e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        GrPathRendererChain::DrawType type = element->isAA() ?
455e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            GrPathRendererChain::kStencilAndColorAntiAlias_DrawType :
456e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            GrPathRendererChain::kStencilAndColor_DrawType;
457e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        *pr = this->getContext()->getPathRenderer(path, stroke, fGpu, false, type);
45849f085dddff10473b6ebf832a974288300224e60bsalomon        return SkToBool(*pr);
459b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    }
460b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com}
461b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
4627b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.comvoid GrClipMaskManager::mergeMask(GrTexture* dstMask,
4637b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                  GrTexture* srcMask,
4647b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                  SkRegion::Op op,
465fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                                  const SkIRect& dstBound,
466fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                                  const SkIRect& srcBound) {
467137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    GrDrawState::AutoViewMatrixRestore avmr;
46813b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
469137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    SkAssertResult(avmr.setIdentity(drawState));
470eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com    GrDrawState::AutoRestoreEffects are(drawState);
471f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4727b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    drawState->setRenderTarget(dstMask->asRenderTarget());
473f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4747b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    setup_boolean_blendcoeffs(drawState, op);
47572b2e6fff3f54c6aa80a98eab4c73f02a8cd450dskia.committer@gmail.com
476b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com    SkMatrix sampleM;
4777b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    sampleM.setIDiv(srcMask->width(), srcMask->height());
478956b310f13c7412c035406c658ff16ca85eac656skia.committer@gmail.com
479b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    drawState->addColorProcessor(
4807b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com        GrTextureDomainEffect::Create(srcMask,
4817b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                      sampleM,
482907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org                                      GrTextureDomain::MakeTexelDomain(srcMask, srcBound),
483907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org                                      GrTextureDomain::kDecal_Mode,
484b86add1ad37776818e1f730359ec587c9fdbff5fhumper@google.com                                      GrTextureParams::kNone_FilterMode))->unref();
48501c8da1eef36570374f7e8764a38b25bf16ab7a6bsalomon    fGpu->drawSimpleRect(SkRect::Make(dstBound));
486f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
487f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4886d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com// get a texture to act as a temporary buffer for AA clip boolean operations
4896d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com// TODO: given the expense of createTexture we may want to just cache this too
4904c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.comvoid GrClipMaskManager::getTemp(int width, int height, GrAutoScratchTexture* temp) {
49149f085dddff10473b6ebf832a974288300224e60bsalomon    if (temp->texture()) {
4926d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com        // we've already allocated the temp texture
4936d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com        return;
4946d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com    }
4956d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
49675b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    GrTextureDesc desc;
49775b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    desc.fFlags = kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit;
4984c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    desc.fWidth = width;
4994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    desc.fHeight = height;
50075b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    desc.fConfig = kAlpha_8_GrPixelConfig;
5016b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
5022c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com    temp->set(this->getContext(), desc);
5036d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com}
5046d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
5056b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
506ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski// Return the texture currently in the cache if it exists. Otherwise, return NULL
507ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevskiGrTexture* GrClipMaskManager::getCachedMaskTexture(int32_t elementsGenID,
508ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski                                                   const SkIRect& clipSpaceIBounds) {
509d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    bool cached = fAACache.canReuse(elementsGenID, clipSpaceIBounds);
5104c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (!cached) {
511ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        return NULL;
512ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    }
5134c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
514ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    return fAACache.getLastMask();
515ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski}
516f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
517ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski////////////////////////////////////////////////////////////////////////////////
518ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski// Allocate a texture in the texture cache. This function returns the texture
519ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski// allocated (or NULL on error).
520ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevskiGrTexture* GrClipMaskManager::allocMaskTexture(int32_t elementsGenID,
521ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski                                               const SkIRect& clipSpaceIBounds,
522ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski                                               bool willUpload) {
523ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    // Since we are setting up the cache we should free up the
524ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    // currently cached mask so it can be reused.
525ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    fAACache.reset();
526a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
527ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    GrTextureDesc desc;
528ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    desc.fFlags = willUpload ? kNone_GrTextureFlags : kRenderTarget_GrTextureFlagBit;
529ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    desc.fWidth = clipSpaceIBounds.width();
530ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    desc.fHeight = clipSpaceIBounds.height();
531ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    desc.fConfig = kRGBA_8888_GrPixelConfig;
532ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    if (willUpload || this->getContext()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
533ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        // We would always like A8 but it isn't supported on all platforms
534ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        desc.fConfig = kAlpha_8_GrPixelConfig;
5358fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com    }
5368fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com
537ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    fAACache.acquireMask(elementsGenID, desc, clipSpaceIBounds);
538ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    return fAACache.getLastMask();
5396b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com}
540f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
5416b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
5426b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Create a 8-bit clip mask in alpha
543d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgGrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
5444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                  InitialState initialState,
5454c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                  const ElementList& elements,
5464c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                  const SkIRect& clipSpaceIBounds) {
547f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(kNone_ClipMaskType == fCurrClipMaskType);
548c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com
549ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    // First, check for cached texture
550ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    GrTexture* result = this->getCachedMaskTexture(elementsGenID, clipSpaceIBounds);
55149f085dddff10473b6ebf832a974288300224e60bsalomon    if (result) {
552c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com        fCurrClipMaskType = kAlpha_ClipMaskType;
5534c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        return result;
5546b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
555f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
556ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    // There's no texture in the cache. Let's try to allocate it then.
557ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    result = this->allocMaskTexture(elementsGenID, clipSpaceIBounds, false);
5584c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (NULL == result) {
559f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com        fAACache.reset();
5604c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        return NULL;
561f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
562f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
5634c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // The top-left of the mask corresponds to the top-left corner of the bounds.
5647b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    SkVector clipToMaskOffset = {
5654c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        SkIntToScalar(-clipSpaceIBounds.fLeft),
5664c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        SkIntToScalar(-clipSpaceIBounds.fTop)
5677b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    };
5684c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // The texture may be larger than necessary, this rect represents the part of the texture
5694c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // we populate with a rasterization of the clip.
5704c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height());
571f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
572137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    // Set the matrix so that rendered clip elements are transformed to mask space from clip space.
573137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    SkMatrix translate;
574137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    translate.setTranslate(clipToMaskOffset);
575137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit, &translate);
576137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com
577137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
578137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com
579cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com    // We're drawing a coverage mask and want coverage to be run through the blend function.
580cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com    drawState->enableState(GrDrawState::kCoverageDrawing_StateBit);
581cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com
5827b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    // The scratch texture that we are drawing into can be substantially larger than the mask. Only
5837b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    // clear the part that we care about.
5844c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    fGpu->clear(&maskSpaceIBounds,
5854c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000,
58656ce48ade325f6f49acb0da31d6252806e4ed7efrobertphillips@google.com                true,
5874c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                result->asRenderTarget());
588d9f7503e0cb0c4db856f53b4bdeec1332db6f296skia.committer@gmail.com
589b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    // When we use the stencil in the below loop it is important to have this clip installed.
590b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    // The second pass that zeros the stencil buffer renders the rect maskSpaceIBounds so the first
591b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    // pass must not set values outside of this bounds or stencil values outside the rect won't be
592b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    // cleared.
593b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    GrDrawTarget::AutoClipRestore acr(fGpu, maskSpaceIBounds);
594b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    drawState->enableState(GrDrawState::kClip_StateBit);
595b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
596f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    GrAutoScratchTexture temp;
597f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // walk through each clip element and perform its set op
5984c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    for (ElementList::Iter iter = elements.headIter(); iter.get(); iter.next()) {
5994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        const Element* element = iter.get();
6008182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        SkRegion::Op op = element->getOp();
601b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        bool invert = element->isInverseFilled();
602f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
603b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) {
604e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com            GrPathRenderer* pr = NULL;
605e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com            bool useTemp = !this->canStencilAndDrawElement(result, element, &pr);
606b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            GrTexture* dst;
6074c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // This is the bounds of the clip element in the space of the alpha-mask. The temporary
6087b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            // mask buffer can be substantially larger than the actually clip stack element. We
6097b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            // touch the minimum number of pixels necessary and use decal mode to combine it with
610b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            // the accumulator.
611fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org            SkIRect maskSpaceElementIBounds;
612b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
613b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            if (useTemp) {
614b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                if (invert) {
615b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                    maskSpaceElementIBounds = maskSpaceIBounds;
616b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                } else {
617fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                    SkRect elementBounds = element->getBounds();
618b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                    elementBounds.offset(clipToMaskOffset);
619b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                    elementBounds.roundOut(&maskSpaceElementIBounds);
620b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                }
621b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
622b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                this->getTemp(maskSpaceIBounds.fRight, maskSpaceIBounds.fBottom, &temp);
623b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                if (NULL == temp.texture()) {
624b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                    fAACache.reset();
625b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                    return NULL;
626a7aedfec9e28db36c97e49f11f2bc2e0eb624c30skia.committer@gmail.com                }
627b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                dst = temp.texture();
628b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                // clear the temp target and set blend to replace
629b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                fGpu->clear(&maskSpaceElementIBounds,
630b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                            invert ? 0xffffffff : 0x00000000,
63156ce48ade325f6f49acb0da31d6252806e4ed7efrobertphillips@google.com                            true,
632b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                            dst->asRenderTarget());
633b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
634a7aedfec9e28db36c97e49f11f2bc2e0eb624c30skia.committer@gmail.com
6354c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            } else {
636b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                // draw directly into the result with the stencil set to make the pixels affected
637b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                // by the clip shape be non-zero.
638b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                dst = result;
639b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                GR_STATIC_CONST_SAME_STENCIL(kStencilInElement,
640b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             kReplace_StencilOp,
641b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             kReplace_StencilOp,
642b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             kAlways_StencilFunc,
643b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             0xffff,
644b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             0xffff,
645b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             0xffff);
646b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                drawState->setStencil(kStencilInElement);
647a7aedfec9e28db36c97e49f11f2bc2e0eb624c30skia.committer@gmail.com                setup_boolean_blendcoeffs(drawState, op);
6484c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            }
6497b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com
650c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com            drawState->setAlpha(invert ? 0x00 : 0xff);
651c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com
652e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com            if (!this->drawElement(dst, element, pr)) {
653e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                fAACache.reset();
654e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                return NULL;
6554c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            }
656f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
657b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            if (useTemp) {
658b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                // Now draw into the accumulator using the real operation and the temp buffer as a
659b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                // texture
660b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                this->mergeMask(result,
661b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                temp.texture(),
662b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                op,
663b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                maskSpaceIBounds,
664b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                maskSpaceElementIBounds);
665b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            } else {
666b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                // Draw to the exterior pixels (those with a zero stencil value).
667b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                drawState->setAlpha(invert ? 0xff : 0x00);
668b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement,
669b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             kZero_StencilOp,
670b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             kZero_StencilOp,
671b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             kEqual_StencilFunc,
672b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             0xffff,
673b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             0x0000,
674b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             0xffff);
675b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                drawState->setStencil(kDrawOutsideElement);
676b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                fGpu->drawSimpleRect(clipSpaceIBounds);
677b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                drawState->disableStencil();
678b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            }
679f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        } else {
680e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com            // all the remaining ops can just be directly draw into the accumulation buffer
681c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com            drawState->setAlpha(0xff);
6826b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            setup_boolean_blendcoeffs(drawState, op);
683b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            this->drawElement(result, element);
684f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        }
685f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
686f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
687c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    fCurrClipMaskType = kAlpha_ClipMaskType;
6884c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    return result;
6891e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
6901e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
691f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
692fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device
693f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com// (as opposed to canvas) coordinates
694d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgbool GrClipMaskManager::createStencilClipMask(int32_t elementsGenID,
695d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                                              InitialState initialState,
6964c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                              const ElementList& elements,
6974c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                              const SkIRect& clipSpaceIBounds,
6984c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                              const SkIPoint& clipSpaceToStencilOffset) {
6991e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
700f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(kNone_ClipMaskType == fCurrClipMaskType);
7011e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
70213b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
703f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(drawState->isClipState());
7041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrRenderTarget* rt = drawState->getRenderTarget();
70649f085dddff10473b6ebf832a974288300224e60bsalomon    SkASSERT(rt);
7071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7081e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // TODO: dynamically attach a SB when needed.
7091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
7101e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    if (NULL == stencilBuffer) {
7111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        return false;
7121e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
7131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
714d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    if (stencilBuffer->mustRenderClip(elementsGenID, clipSpaceIBounds, clipSpaceToStencilOffset)) {
7151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
716d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org        stencilBuffer->setLastClip(elementsGenID, clipSpaceIBounds, clipSpaceToStencilOffset);
7171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
718137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        // Set the matrix so that rendered clip elements are transformed from clip to stencil space.
719137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        SkVector translate = {
720137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com            SkIntToScalar(clipSpaceToStencilOffset.fX),
721137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com            SkIntToScalar(clipSpaceToStencilOffset.fY)
722137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        };
723137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        SkMatrix matrix;
724137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        matrix.setTranslate(translate);
725137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit, &matrix);
72613b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com        drawState = fGpu->drawState();
727137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com
7281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        drawState->setRenderTarget(rt);
7291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7309f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com        // We set the current clip to the bounds so that our recursive draws are scissored to them.
7319f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com        SkIRect stencilSpaceIBounds(clipSpaceIBounds);
7329f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com        stencilSpaceIBounds.offset(clipSpaceToStencilOffset);
7339f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com        GrDrawTarget::AutoClipRestore acr(fGpu, stencilSpaceIBounds);
7349f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com        drawState->enableState(GrDrawState::kClip_StateBit);
7359f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com
7361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#if !VISUALIZE_COMPLEX_CLIP
7371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
7381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#endif
7391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7401e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        int clipBit = stencilBuffer->bits();
7414c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers");
7421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        clipBit = (1 << (clipBit-1));
7431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
744b0bd4f64a6827dda6f4ec48e4746b0f0b72a975fbsalomon        fGpu->clearStencilClip(rt, stencilSpaceIBounds, kAllIn_InitialState == initialState);
7451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // walk through each clip element and perform its set op
7471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // with the existing clip.
74849f085dddff10473b6ebf832a974288300224e60bsalomon        for (ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) {
7494c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            const Element* element = iter.get();
7508afae61a57f87e4a50578effce6c428031499301tomhudson@google.com            bool fillInverted = false;
7511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // enabled at bottom of loop
7521e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            drawState->disableState(GrGpu::kModifyStencilClip_StateBit);
753ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            // if the target is MSAA then we want MSAA enabled when the clip is soft
754ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            if (rt->isMultisampled()) {
7558182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                drawState->setState(GrDrawState::kHWAntialias_StateBit, element->isAA());
756ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            }
7571e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
75845a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com            // This will be used to determine whether the clip shape can be rendered into the
75945a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com            // stencil with arbitrary stencil settings.
76045a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com            GrPathRenderer::StencilSupport stencilSupport;
7611e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7625f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
76312b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com
7648182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            SkRegion::Op op = element->getOp();
765f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
766e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com            GrPathRenderer* pr = NULL;
767e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            SkPath clipPath;
7688182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            if (Element::kRect_Type == element->getType()) {
76945a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport;
7701e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                fillInverted = false;
7718afae61a57f87e4a50578effce6c428031499301tomhudson@google.com            } else {
772e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                element->asPath(&clipPath);
773e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                fillInverted = clipPath.isInverseFillType();
774e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                if (fillInverted) {
775e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                    clipPath.toggleInverseFillType();
776e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                }
777e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                pr = this->getContext()->getPathRenderer(clipPath,
77845a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                                         stroke,
77945a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                                         fGpu,
78045a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                                         false,
78145a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                                         GrPathRendererChain::kStencilOnly_DrawType,
782e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                                                         &stencilSupport);
783e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                if (NULL == pr) {
7841e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    return false;
7851e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
7861e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
7871e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7881e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            int passes;
7891e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
7901e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
79145a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com            bool canRenderDirectToStencil =
79245a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport;
7931e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            bool canDrawDirectToClip; // Given the renderer, the element,
7944c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                      // fill rule, and set operation can
7954c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                      // we render the element directly to
7964c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                      // stencil bit used for clipping.
7974c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            canDrawDirectToClip = GrStencilSettings::GetClipPasses(op,
7984c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                                   canRenderDirectToStencil,
7994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                                   clipBit,
8004c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                                   fillInverted,
8014c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                                   &passes,
8024c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                                   stencilSettings);
8031e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // draw the element to the client stencil bits if necessary
8051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            if (!canDrawDirectToClip) {
8061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
8074c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                             kIncClamp_StencilOp,
8084c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                             kIncClamp_StencilOp,
8094c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                             kAlways_StencilFunc,
8104c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                             0xffff,
8114c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                             0x0000,
8124c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                             0xffff);
8131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                SET_RANDOM_COLOR
8148182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                if (Element::kRect_Type == element->getType()) {
8151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    *drawState->stencil() = gDrawToStencil;
81601c8da1eef36570374f7e8764a38b25bf16ab7a6bsalomon                    fGpu->drawSimpleRect(element->getRect());
8171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
818e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                    if (!clipPath.isEmpty()) {
81919dd017a6256be636ccb550752bb563c4e7caeb5commit-bot@chromium.org                        if (canRenderDirectToStencil) {
82019dd017a6256be636ccb550752bb563c4e7caeb5commit-bot@chromium.org                            *drawState->stencil() = gDrawToStencil;
821e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                            pr->drawPath(clipPath, stroke, fGpu, false);
82219dd017a6256be636ccb550752bb563c4e7caeb5commit-bot@chromium.org                        } else {
823e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                            pr->stencilPath(clipPath, stroke, fGpu);
82419dd017a6256be636ccb550752bb563c4e7caeb5commit-bot@chromium.org                        }
8251e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    }
8261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
8271e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
8281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // now we modify the clip bit by rendering either the clip
8301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // element directly or a bounding rect of the entire clip.
8311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            drawState->enableState(GrGpu::kModifyStencilClip_StateBit);
8321e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            for (int p = 0; p < passes; ++p) {
8331e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                *drawState->stencil() = stencilSettings[p];
8341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (canDrawDirectToClip) {
8358182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    if (Element::kRect_Type == element->getType()) {
8361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        SET_RANDOM_COLOR
83701c8da1eef36570374f7e8764a38b25bf16ab7a6bsalomon                        fGpu->drawSimpleRect(element->getRect());
8381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    } else {
8391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        SET_RANDOM_COLOR
840e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                        pr->drawPath(clipPath, stroke, fGpu, false);
8411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    }
8421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
8431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    SET_RANDOM_COLOR
8444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    // The view matrix is setup to do clip space -> stencil space translation, so
8454c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    // draw rect in clip space.
84601c8da1eef36570374f7e8764a38b25bf16ab7a6bsalomon                    fGpu->drawSimpleRect(SkRect::Make(clipSpaceIBounds));
8471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
8481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
8491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        }
8501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
851c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    // set this last because recursive draws may overwrite it back to kNone.
852f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(kNone_ClipMaskType == fCurrClipMaskType);
853c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    fCurrClipMaskType = kStencil_ClipMaskType;
8541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    return true;
8551e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
8561e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
857f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com
858411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com// mapping of clip-respecting stencil funcs to normal stencil funcs
859411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com// mapping depends on whether stencil-clipping is in effect.
860fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comstatic const GrStencilFunc
861411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    gSpecialToBasicStencilFunc[2][kClipStencilFuncCount] = {
862411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    {// Stencil-Clipping is DISABLED,  we are effectively always inside the clip
863411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // In the Clip Funcs
864411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kAlways_StencilFunc,          // kAlwaysIfInClip_StencilFunc
865411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
866411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLess_StencilFunc,            // kLessIfInClip_StencilFunc
867411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
868411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // Special in the clip func that forces user's ref to be 0.
869411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kNotEqual_StencilFunc,        // kNonZeroIfInClip_StencilFunc
870411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // make ref 0 and do normal nequal.
871411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    },
872411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    {// Stencil-Clipping is ENABLED
873411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // In the Clip Funcs
874411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kEqual_StencilFunc,           // kAlwaysIfInClip_StencilFunc
875411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // eq stencil clip bit, mask
876411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // out user bits.
877411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
878411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
879411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // add stencil bit to mask and ref
880411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
881411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLess_StencilFunc,            // kLessIfInClip_StencilFunc
882411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
883411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // for both of these we can add
884411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // the clip bit to the mask and
885411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // ref and compare as normal
886411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // Special in the clip func that forces user's ref to be 0.
887411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLess_StencilFunc,            // kNonZeroIfInClip_StencilFunc
888411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // make ref have only the clip bit set
889411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // and make comparison be less
890411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // 10..0 < 1..user_bits..
891411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    }
892411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com};
893411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
894a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comnamespace {
895a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com// Sets the settings to clip against the stencil buffer clip while ignoring the
896a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com// client bits.
897a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comconst GrStencilSettings& basic_apply_stencil_clip_settings() {
898a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // stencil settings to use when clip is in stencil
899a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
900a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kKeep_StencilOp,
901a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kKeep_StencilOp,
902a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kAlwaysIfInClip_StencilFunc,
903a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        0x0000,
904a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        0x0000,
905fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        0x0000);
906a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
907a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com}
908a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com}
909a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
910a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comvoid GrClipMaskManager::setGpuStencil() {
911a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // We make two copies of the StencilSettings here (except in the early
912a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // exit scenario. One copy from draw state to the stack var. Then another
913a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // from the stack var to the gpu. We could make this class hold a ptr to
914a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // GrGpu's fStencilSettings and eliminate the stack copy here.
915a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
916a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    const GrDrawState& drawState = fGpu->getDrawState();
917a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
918a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // use stencil for clipping if clipping is enabled and the clip
919a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // has been written into the stencil.
920a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrClipMaskManager::StencilClipMode clipMode;
921a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    if (this->isClipInStencil() && drawState.isClipState()) {
922a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        clipMode = GrClipMaskManager::kRespectClip_StencilClipMode;
923a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        // We can't be modifying the clip and respecting it at the same time.
924f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(!drawState.isStateFlagEnabled(
925a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    GrGpu::kModifyStencilClip_StateBit));
926a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    } else if (drawState.isStateFlagEnabled(
927a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    GrGpu::kModifyStencilClip_StateBit)) {
928a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        clipMode = GrClipMaskManager::kModifyClip_StencilClipMode;
929a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    } else {
930a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode;
931a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
932a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
933a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrStencilSettings settings;
934a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // The GrGpu client may not be using the stencil buffer but we may need to
935a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // enable it in order to respect a stencil clip.
936a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    if (drawState.getStencil().isDisabled()) {
937a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        if (GrClipMaskManager::kRespectClip_StencilClipMode == clipMode) {
938a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            settings = basic_apply_stencil_clip_settings();
939a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        } else {
940a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            fGpu->disableStencil();
941a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            return;
942a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        }
943a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    } else {
944a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings = drawState.getStencil();
945a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
946a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
947a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // TODO: dynamically attach a stencil buffer
948a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    int stencilBits = 0;
949fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    GrStencilBuffer* stencilBuffer =
950a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        drawState.getRenderTarget()->getStencilBuffer();
95149f085dddff10473b6ebf832a974288300224e60bsalomon    if (stencilBuffer) {
952a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        stencilBits = stencilBuffer->bits();
953a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
954a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
955f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(fGpu->caps()->stencilWrapOpsSupport() || !settings.usesWrapOp());
956f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(fGpu->caps()->twoSidedStencilSupport() || !settings.isTwoSided());
957a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    this->adjustStencilParams(&settings, clipMode, stencilBits);
958a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    fGpu->setStencilSettings(settings);
959a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com}
960a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
961a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comvoid GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings,
962a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                                            StencilClipMode mode,
963a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                                            int stencilBitCnt) {
964f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(stencilBitCnt > 0);
965411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
966411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    if (kModifyClip_StencilClipMode == mode) {
967a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        // We assume that this clip manager itself is drawing to the GrGpu and
968a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        // has already setup the correct values.
969a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        return;
970411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    }
971a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
972411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    unsigned int clipBit = (1 << (stencilBitCnt - 1));
973411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    unsigned int userBits = clipBit - 1;
974411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
975a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrStencilSettings::Face face = GrStencilSettings::kFront_Face;
976bcce8926524827775539874346dd424a9510dbc9bsalomon@google.com    bool twoSided = fGpu->caps()->twoSidedStencilSupport();
977a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
978a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    bool finished = false;
979a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    while (!finished) {
980a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        GrStencilFunc func = settings->func(face);
981a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        uint16_t writeMask = settings->writeMask(face);
982a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        uint16_t funcMask = settings->funcMask(face);
983a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        uint16_t funcRef = settings->funcRef(face);
984a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
985f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT((unsigned) func < kStencilFuncCount);
986a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
987a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        writeMask &= userBits;
988a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
989a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        if (func >= kBasicStencilFuncCount) {
990a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            int respectClip = kRespectClip_StencilClipMode == mode;
991a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            if (respectClip) {
992a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                // The GrGpu class should have checked this
993f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org                SkASSERT(this->isClipInStencil());
994a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                switch (func) {
995a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kAlwaysIfInClip_StencilFunc:
996a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcMask = clipBit;
997a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcRef = clipBit;
998a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        break;
999a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kEqualIfInClip_StencilFunc:
1000a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kLessIfInClip_StencilFunc:
1001a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kLEqualIfInClip_StencilFunc:
1002a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcMask = (funcMask & userBits) | clipBit;
1003a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcRef  = (funcRef  & userBits) | clipBit;
1004a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        break;
1005a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kNonZeroIfInClip_StencilFunc:
1006a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcMask = (funcMask & userBits) | clipBit;
1007a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcRef = clipBit;
1008a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        break;
1009a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    default:
101088cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org                        SkFAIL("Unknown stencil func");
1011a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                }
1012a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            } else {
1013a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                funcMask &= userBits;
1014a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                funcRef &= userBits;
1015411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com            }
1016fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com            const GrStencilFunc* table =
1017a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                gSpecialToBasicStencilFunc[respectClip];
1018a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            func = table[func - kBasicStencilFuncCount];
1019f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org            SkASSERT(func >= 0 && func < kBasicStencilFuncCount);
1020411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        } else {
1021a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            funcMask &= userBits;
1022a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            funcRef &= userBits;
1023411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        }
1024a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1025a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->setFunc(face, func);
1026a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->setWriteMask(face, writeMask);
1027a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->setFuncMask(face, funcMask);
1028a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->setFuncRef(face, funcRef);
1029a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1030a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        if (GrStencilSettings::kFront_Face == face) {
1031a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            face = GrStencilSettings::kBack_Face;
1032a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            finished = !twoSided;
1033a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        } else {
1034a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            finished = true;
1035a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        }
1036a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
1037a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    if (!twoSided) {
1038a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->copyFrontSettingsToBack();
1039411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    }
1040411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com}
1041411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
1042411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com////////////////////////////////////////////////////////////////////////////////
1043d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgGrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID,
10444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                     GrReducedClip::InitialState initialState,
10454c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                     const GrReducedClip::ElementList& elements,
10464c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                     const SkIRect& clipSpaceIBounds) {
1047f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(kNone_ClipMaskType == fCurrClipMaskType);
10486b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1049ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    GrTexture* result = this->getCachedMaskTexture(elementsGenID, clipSpaceIBounds);
105049f085dddff10473b6ebf832a974288300224e60bsalomon    if (result) {
10514c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        return result;
10526b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
10536b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
10544c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // The mask texture may be larger than necessary. We round out the clip space bounds and pin
10554c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // the top left corner of the resulting rect to the top left of the texture.
10564c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height());
10574c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
10582c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com    GrSWMaskHelper helper(this->getContext());
10596b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1060b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com    SkMatrix matrix;
10614c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    matrix.setTranslate(SkIntToScalar(-clipSpaceIBounds.fLeft),
10624c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                        SkIntToScalar(-clipSpaceIBounds.fTop));
106371614ac7c63fe60dfe971f861e2b2d6325dd0039krajcevski    helper.init(maskSpaceIBounds, &matrix, false);
10644c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
10654c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    helper.clear(kAllIn_InitialState == initialState ? 0xFF : 0x00);
1066fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
10675f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
106812b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com
106949f085dddff10473b6ebf832a974288300224e60bsalomon    for (ElementList::Iter iter(elements.headIter()) ; iter.get(); iter.next()) {
1070fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
10714c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        const Element* element = iter.get();
10728182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        SkRegion::Op op = element->getOp();
1073fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
10744c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        if (SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) {
10754c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // Intersect and reverse difference require modifying pixels outside of the geometry
10764c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // that is being "drawn". In both cases we erase all the pixels outside of the geometry
10774c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // but leave the pixels inside the geometry alone. For reverse difference we invert all
10784c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // the pixels before clearing the ones outside the geometry.
1079fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            if (SkRegion::kReverseDifference_Op == op) {
10804469938e92d779dff05e745559e67907bbf21e78reed@google.com                SkRect temp = SkRect::Make(clipSpaceIBounds);
1081fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                // invert the entire scene
1082366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com                helper.draw(temp, SkRegion::kXOR_Op, false, 0xFF);
1083fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            }
1084fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
10855c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org            SkPath clipPath;
10865c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org            element->asPath(&clipPath);
10875c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org            clipPath.toggleInverseFillType();
10885c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org            helper.draw(clipPath, stroke, SkRegion::kReplace_Op, element->isAA(), 0x00);
1089fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1090fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            continue;
1091fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        }
1092fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1093fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        // The other ops (union, xor, diff) only affect pixels inside
1094fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        // the geometry so they can just be drawn normally
10958182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        if (Element::kRect_Type == element->getType()) {
10968182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            helper.draw(element->getRect(), op, element->isAA(), 0xFF);
10978182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        } else {
10985c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org            SkPath path;
10995c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org            element->asPath(&path);
11005c056399259bb7ec06ff1eb8ce904001b363276ccommit-bot@chromium.org            helper.draw(path, stroke, op, element->isAA(), 0xFF);
11016b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        }
11026b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
11036b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1104ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    // Allocate clip mask texture
1105ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    result = this->allocMaskTexture(elementsGenID, clipSpaceIBounds, true);
1106ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    if (NULL == result) {
1107ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        fAACache.reset();
1108ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        return NULL;
1109ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    }
1110d92cf2ebbfbb9d737ea4a551e64ffccb08376875robertphillips@google.com    helper.toTexture(result);
11116b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1112c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    fCurrClipMaskType = kAlpha_ClipMaskType;
11134c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    return result;
11146b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com}
11156b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1116f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
1117c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomonvoid GrClipMaskManager::purgeResources() {
1118c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon    fAACache.purgeResources();
11191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
11206e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.com
11216e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.comvoid GrClipMaskManager::setGpu(GrGpu* gpu) {
11226e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.com    fGpu = gpu;
11236e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.com    fAACache.setContext(gpu->getContext());
11246e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.com}
1125c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org
1126c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.orgvoid GrClipMaskManager::adjustPathStencilParams(GrStencilSettings* settings) {
1127c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org    const GrDrawState& drawState = fGpu->getDrawState();
1128c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org    GrClipMaskManager::StencilClipMode clipMode;
1129c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org    if (this->isClipInStencil() && drawState.isClipState()) {
1130c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org        clipMode = GrClipMaskManager::kRespectClip_StencilClipMode;
1131c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org        // We can't be modifying the clip and respecting it at the same time.
1132c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org        SkASSERT(!drawState.isStateFlagEnabled(
1133c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org                    GrGpu::kModifyStencilClip_StateBit));
1134c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org    } else if (drawState.isStateFlagEnabled(
1135c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org                    GrGpu::kModifyStencilClip_StateBit)) {
1136c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org        clipMode = GrClipMaskManager::kModifyClip_StencilClipMode;
1137c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org    } else {
1138c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org        clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode;
1139c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org    }
1140c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org
1141c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org    // TODO: dynamically attach a stencil buffer
1142c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org    int stencilBits = 0;
1143c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org    GrStencilBuffer* stencilBuffer =
1144c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org        drawState.getRenderTarget()->getStencilBuffer();
114549f085dddff10473b6ebf832a974288300224e60bsalomon    if (stencilBuffer) {
1146c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org        stencilBits = stencilBuffer->bits();
1147c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org        this->adjustStencilParams(settings, clipMode, stencilBits);
1148c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org    }
1149c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org}
1150