GrClipMaskManager.cpp revision 8a4fc40b02fa0a8300ade26863f4ddae69197d62
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"
101e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrGpu.h"
111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrRenderTarget.h"
121e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrStencilBuffer.h"
131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrPathRenderer.h"
14a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com#include "GrPaint.h"
156b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com#include "SkRasterClip.h"
16fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com#include "GrAAConvexPathRenderer.h"
17fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com#include "GrAAHairLinePathRenderer.h"
18fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
19fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com// TODO: move GrSWMaskHelper out of GrSoftwarePathRender.h & remove this include
20fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com#include "GrSoftwarePathRenderer.h"
21a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
22a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com//#define GR_AA_CLIP 1
236b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com//#define GR_SW_CLIP 1
24a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
25f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.comvoid ScissoringSettings::setupScissoring(GrGpu* gpu) {
271e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    if (!fEnableScissoring) {
281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        gpu->disableScissor();
291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        return;
301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
321e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    gpu->enableScissoring(fScissorRect);
331e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
35a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.comnamespace {
36a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com// set up the draw state to enable the aa clipping mask. Besides setting up the
37a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com// sampler matrix this also alters the vertex layout
386b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.comvoid setup_drawstate_aaclip(GrGpu* gpu,
396b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                            GrTexture* result,
406623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                            const GrIRect &bound) {
41a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    GrDrawState* drawState = gpu->drawState();
42a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    GrAssert(drawState);
43a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
44a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    static const int maskStage = GrPaint::kTotalStages+1;
45a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
46a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    GrMatrix mat;
47a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    mat.setIDiv(result->width(), result->height());
486623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com    mat.preTranslate(SkIntToScalar(-bound.fLeft), SkIntToScalar(-bound.fTop));
49a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    mat.preConcat(drawState->getViewMatrix());
50a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
51a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    drawState->sampler(maskStage)->reset(GrSamplerState::kClamp_WrapMode,
52a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com                                         GrSamplerState::kNearest_Filter,
53a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com                                         mat);
54a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
55a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    drawState->setTexture(maskStage, result);
56a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
57a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    // The AA clipping determination happens long after the geometry has
58a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    // been set up to draw. Here we directly enable the AA clip mask stage
59a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    gpu->addToVertexLayout(
60a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com                GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(maskStage));
61a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com}
62a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
638a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.combool path_needs_SW_renderer(GrContext* context,
648a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                           GrGpu* gpu,
658a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                           const SkPath& path,
668a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                           GrPathFill fill,
678a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                           bool doAA) {
688a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com    // last (false) parameter disallows use of the SW path renderer
698a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com    return NULL == context->getPathRenderer(path, fill, gpu, doAA, false);
708a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com}
718a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com
726b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com}
736b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
74fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com/*
75fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * This method traverses the clip stack to see if the GrSoftwarePathRenderer
76fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * will be used on any element. If so, it returns true to indicate that the
77fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * entire clip should be rendered in SW and then uploaded en masse to the gpu.
78fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com */
79fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.combool GrClipMaskManager::useSWOnlyPath(GrGpu* gpu, const GrClip& clipIn) {
80a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com
81a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    if (!clipIn.requiresAA()) {
82a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com        // The stencil buffer can handle this case
83a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com        return false;
84a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    }
85fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
868a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com    // TODO: generalize this function so that when
87fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // a clip gets complex enough it can just be done in SW regardless
88fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // of whether it would invoke the GrSoftwarePathRenderer.
89fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    bool useSW = false;
90fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
91fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    for (int i = 0; i < clipIn.getElementCount(); ++i) {
92fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
93fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        if (SkRegion::kReplace_Op == clipIn.getOp(i)) {
94fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // Everything before a replace op can be ignored so start
95fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // afresh w.r.t. determining if any element uses the SW path
96fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            useSW = false;
97fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        }
98fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
99fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        if (kRect_ClipType == clipIn.getElementType(i)) {
1008a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com            // Non-anti-aliased rects can always be drawn directly (w/o
1018a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com            // using the software path) so the anti-aliased rects are all
1028a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com            // that need to be checked here
1038a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com            if (clipIn.getDoAA(i)) {
1048a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                // Antialiased rects are converted to paths and then drawn with
1058a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                // kEvenOdd_PathFill.
1068a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com
1078a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                // TODO: wrap GrContext::fillAARect in a helper class and
1088a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                // draw AA rects directly rather than converting to paths
1098a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                SkPath temp;
1108a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                temp.addRect(clipIn.getRect(i));
1118a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com
1128a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                if (path_needs_SW_renderer(this->getContext(), gpu, temp,
1138a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                                           kEvenOdd_PathFill, true)) {
1148a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                    useSW = true;
1158a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                }
1168a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com            }
1178a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com        } else {
1188a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com            if (path_needs_SW_renderer(this->getContext(), gpu,
1198a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                                       clipIn.getPath(i),
1208a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                                       clipIn.getPathFill(i),
1218a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com                                       clipIn.getDoAA(i))) {
122fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                useSW = true;
123fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            }
124fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        }
125fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    }
126fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
127fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    return useSW;
128a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com}
129a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
130f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
1316b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// sort out what kind of clip mask needs to be created: alpha, stencil,
1326b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// scissor, or entirely software
1331e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.combool GrClipMaskManager::createClipMask(GrGpu* gpu,
1341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                       const GrClip& clipIn,
1351e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                       ScissoringSettings* scissorSettings) {
1361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
1371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrAssert(scissorSettings);
1381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
1391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    scissorSettings->fEnableScissoring = false;
1401e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    fClipMaskInStencil = false;
141f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    fClipMaskInAlpha = false;
1421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
1431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrDrawState* drawState = gpu->drawState();
1441e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    if (!drawState->isClipState()) {
1451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        return true;
1461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
1471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
1481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrRenderTarget* rt = drawState->getRenderTarget();
1491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
1501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // GrDrawTarget should have filtered this for us
1511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrAssert(NULL != rt);
1521e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
1536b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com#if GR_SW_CLIP
154a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    // If MSAA is enabled we can do everything in the stencil buffer.
155a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    // Otherwise check if we should just create the entire clip mask
156a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    // in software (this will only happen if the clip mask is anti-aliased
157a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    // and too complex for the gpu to handle in its entirety)
158a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    if (0 == rt->numSamples() && useSWOnlyPath(gpu, clipIn)) {
1596b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        // The clip geometry is complex enough that it will be more
1606b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        // efficient to create it entirely in software
1616b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        GrTexture* result = NULL;
1626623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com        GrIRect bound;
1636b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        if (this->createSoftwareClipMask(gpu, clipIn, &result, &bound)) {
1646b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            fClipMaskInAlpha = true;
1656b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1666b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            setup_drawstate_aaclip(gpu, result, bound);
1676b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            return true;
1686b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        }
169a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com
170a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com        // if SW clip mask creation fails fall through to the other
171a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com        // two possible methods (bottoming out at stencil clipping)
1726b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
173a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com#endif // GR_SW_CLIP
1746b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
175f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com#if GR_AA_CLIP
176f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // If MSAA is enabled use the (faster) stencil path for AA clipping
177f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // otherwise the alpha clip mask is our only option
178a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    if (0 == rt->numSamples() && clipIn.requiresAA()) {
179f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // Since we are going to create a destination texture of the correct
180f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // size for the mask (rather than being bound by the size of the
181f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // render target) we aren't going to use scissoring like the stencil
182f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // path does (see scissorSettings below)
183a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com        GrTexture* result = NULL;
1846623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com        GrIRect bound;
185a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com        if (this->createAlphaClipMask(gpu, clipIn, &result, &bound)) {
186f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            fClipMaskInAlpha = true;
187a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
1886b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            setup_drawstate_aaclip(gpu, result, bound);
189f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            return true;
190f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        }
191f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
192f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // if alpha clip mask creation fails fall through to the stencil
193f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // buffer method
194f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
195f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com#endif // GR_AA_CLIP
196f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
1975acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    // Either a hard (stencil buffer) clip was explicitly requested or
1985acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    // an antialiased clip couldn't be created. In either case, free up
1995acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    // the texture in the antialiased mask cache.
2005acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    // TODO: this may require more investigation. Ganesh performs a lot of
201a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    // utility draws (e.g., clears, InOrderDrawBuffer playbacks) that hit
202a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    // the stencil buffer path. These may be "incorrectly" clearing the
2035acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    // AA cache.
2045acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    fAACache.reset();
2055acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com
2061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrRect bounds;
2071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrRect rtRect;
2081e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    rtRect.setLTRB(0, 0,
209fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                   GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
2101e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    if (clipIn.hasConservativeBounds()) {
2111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        bounds = clipIn.getConservativeBounds();
2121e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        if (!bounds.intersect(rtRect)) {
2131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            bounds.setEmpty();
2141e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        }
2151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    } else {
2161e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        bounds = rtRect;
2171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
2181e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    bounds.roundOut(&scissorSettings->fScissorRect);
2201e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    if  (scissorSettings->fScissorRect.isEmpty()) {
2211e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        scissorSettings->fScissorRect.setLTRB(0,0,0,0);
2221e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // TODO: I think we can do an early exit here - after refactoring try:
2231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        //  set fEnableScissoring to true but leave fClipMaskInStencil false
2241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        //  and return - everything is going to be scissored away anyway!
2251e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
2261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    scissorSettings->fEnableScissoring = true;
2271e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // use the stencil clip if we can't represent the clip as a rectangle.
2291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    fClipMaskInStencil = !clipIn.isRect() && !clipIn.isEmpty() &&
2301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                         !bounds.isEmpty();
2311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2321e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    if (fClipMaskInStencil) {
2331e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        return this->createStencilClipMask(gpu, clipIn, bounds, scissorSettings);
2341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
2351e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    return true;
2371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
2381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#define VISUALIZE_COMPLEX_CLIP 0
2401e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#if VISUALIZE_COMPLEX_CLIP
2421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    #include "GrRandom.h"
2431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrRandom gRandom;
2441e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    #define SET_RANDOM_COLOR drawState->setColor(0xff000000 | gRandom.nextU());
2451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#else
2461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    #define SET_RANDOM_COLOR
2471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#endif
2481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.comnamespace {
2506623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com/**
2516623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com * Does "container" contain "containee"? If either is empty then
2526623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com * no containment is possible.
2536623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com */
2546623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.combool contains(const SkRect& container, const SkIRect& containee) {
2556623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com    return  !containee.isEmpty() && !container.isEmpty() &&
2566623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com            container.fLeft <= SkIntToScalar(containee.fLeft) &&
2576623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com            container.fTop <= SkIntToScalar(containee.fTop) &&
2586623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com            container.fRight >= SkIntToScalar(containee.fRight) &&
2596623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com            container.fBottom >= SkIntToScalar(containee.fBottom);
2606623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com}
2616623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com
2626623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com
263f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
2641e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com// determines how many elements at the head of the clip can be skipped and
2651e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com// whether the initial clear should be to the inside- or outside-the-clip value,
2661e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com// and what op should be used to draw the first element that isn't skipped.
2671e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.comint process_initial_clip_elements(const GrClip& clip,
2686623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                                  const GrIRect& bounds,
2691e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                  bool* clearToInside,
2700f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com                                  SkRegion::Op* startOp) {
2711e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2721e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // logically before the first element of the clip stack is
2731e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // processed the clip is entirely open. However, depending on the
2741e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // first set op we may prefer to clear to 0 for performance. We may
2751e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // also be able to skip the initial clip paths/rects. We loop until
2761e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // we cannot skip an element.
2771e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    int curr;
2781e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    bool done = false;
2791e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    *clearToInside = true;
2801e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    int count = clip.getElementCount();
2811e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2821e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    for (curr = 0; curr < count && !done; ++curr) {
2831e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        switch (clip.getOp(curr)) {
2840f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com            case SkRegion::kReplace_Op:
2851e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // replace ignores everything previous
2860f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com                *startOp = SkRegion::kReplace_Op;
2871e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                *clearToInside = false;
2881e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                done = true;
2891e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                break;
2900f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com            case SkRegion::kIntersect_Op:
2911e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // if this element contains the entire bounds then we
2921e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // can skip it.
2931e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (kRect_ClipType == clip.getElementType(curr)
2946623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                    && contains(clip.getRect(curr), bounds)) {
2951e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    break;
2961e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
2971e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // if everything is initially clearToInside then intersect is
2981e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // same as clear to 0 and treat as a replace. Otherwise,
2991e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // set stays empty.
3001e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (*clearToInside) {
3010f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com                    *startOp = SkRegion::kReplace_Op;
3021e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    *clearToInside = false;
3031e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    done = true;
3041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
3051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                break;
3061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // we can skip a leading union.
3070f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com            case SkRegion::kUnion_Op:
3081e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // if everything is initially outside then union is
3091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // same as replace. Otherwise, every pixel is still
3101e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // clearToInside
3111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (!*clearToInside) {
3120f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com                    *startOp = SkRegion::kReplace_Op;
3131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    done = true;
3141e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
3151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                break;
3160f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com            case SkRegion::kXOR_Op:
3171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // xor is same as difference or replace both of which
3181e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // can be 1-pass instead of 2 for xor.
3191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (*clearToInside) {
3200f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com                    *startOp = SkRegion::kDifference_Op;
3211e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
3220f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com                    *startOp = SkRegion::kReplace_Op;
3231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
3241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                done = true;
3251e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                break;
3260f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com            case SkRegion::kDifference_Op:
3271e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // if all pixels are clearToInside then we have to process the
3281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // difference, otherwise it has no effect and all pixels
3291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // remain outside.
3301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (*clearToInside) {
3310f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com                    *startOp = SkRegion::kDifference_Op;
3321e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    done = true;
3331e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
3341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                break;
3350f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com            case SkRegion::kReverseDifference_Op:
3361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // if all pixels are clearToInside then reverse difference
3371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // produces empty set. Otherise it is same as replace
3381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (*clearToInside) {
3391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    *clearToInside = false;
3401e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
3410f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com                    *startOp = SkRegion::kReplace_Op;
3421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    done = true;
3431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
3441e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                break;
3451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            default:
3461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                GrCrash("Unknown set op.");
3471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        }
3481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
3491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    return done ? curr-1 : count;
3501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
351f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
352f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
353f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
354f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
355f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.comnamespace {
356f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
357f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
358f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com// set up the OpenGL blend function to perform the specified
359f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com// boolean operation for alpha clip mask creation
3606b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.comvoid setup_boolean_blendcoeffs(GrDrawState* drawState, SkRegion::Op op) {
361f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
362f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    switch (op) {
363f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kReplace_Op:
364f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
365f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
366f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kIntersect_Op:
367f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            drawState->setBlendFunc(kDC_BlendCoeff, kZero_BlendCoeff);
368f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
369f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kUnion_Op:
370f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            drawState->setBlendFunc(kOne_BlendCoeff, kISC_BlendCoeff);
371f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
372f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kXOR_Op:
373f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            drawState->setBlendFunc(kIDC_BlendCoeff, kISC_BlendCoeff);
374f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
375f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kDifference_Op:
376f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            drawState->setBlendFunc(kZero_BlendCoeff, kISC_BlendCoeff);
377f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
378f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kReverseDifference_Op:
379f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            drawState->setBlendFunc(kIDC_BlendCoeff, kZero_BlendCoeff);
380f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
381f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        default:
382f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            GrAssert(false);
383f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
384f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
385f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
386f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
387f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
3882c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.combool draw_path(GrContext* context,
3892c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com               GrGpu* gpu,
3902c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com               const SkPath& path,
3912c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com               GrPathFill fill,
3922c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com               bool doAA) {
393f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
39472176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com    GrPathRenderer* pr = context->getPathRenderer(path, fill, gpu, doAA, true);
395f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    if (NULL == pr) {
396f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        return false;
397f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
398f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
399f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    pr->drawPath(path, fill, NULL, gpu, 0, doAA);
400f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    return true;
401f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
40272176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com
40372176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com}
404f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
405f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
406f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.combool GrClipMaskManager::drawClipShape(GrGpu* gpu,
407f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                                      GrTexture* target,
408f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                                      const GrClip& clipIn,
409f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                                      int index) {
410f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrDrawState* drawState = gpu->drawState();
411f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrAssert(NULL != drawState);
412f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
413f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    drawState->setRenderTarget(target->asRenderTarget());
414f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
415f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    if (kRect_ClipType == clipIn.getElementType(index)) {
416f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        if (clipIn.getDoAA(index)) {
417f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // convert the rect to a path for AA
418f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            SkPath temp;
419f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            temp.addRect(clipIn.getRect(index));
420f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4212c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com            return draw_path(this->getContext(), gpu, temp,
4222c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com                             kEvenOdd_PathFill, clipIn.getDoAA(index));
423f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        } else {
424f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            gpu->drawSimpleRect(clipIn.getRect(index), NULL, 0);
425f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        }
426f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    } else {
4272c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com        return draw_path(this->getContext(), gpu,
4282c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com                         clipIn.getPath(index),
4292c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com                         clipIn.getPathFill(index),
4302c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com                         clipIn.getDoAA(index));
431f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
432f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    return true;
433f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
434f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
435f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.comvoid GrClipMaskManager::drawTexture(GrGpu* gpu,
436f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                                    GrTexture* target,
437f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                                    GrTexture* texture) {
438f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrDrawState* drawState = gpu->drawState();
439f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrAssert(NULL != drawState);
440f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
441f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // no AA here since it is encoded in the texture
442f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    drawState->setRenderTarget(target->asRenderTarget());
443f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
444f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrMatrix sampleM;
445f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    sampleM.setIDiv(texture->width(), texture->height());
446f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    drawState->setTexture(0, texture);
447f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
448f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
449f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                                 GrSamplerState::kNearest_Filter,
450f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                                 sampleM);
451f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
452f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    GrRect rect = GrRect::MakeWH(SkIntToScalar(target->width()),
453f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com                                 SkIntToScalar(target->height()));
454f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com
455f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    gpu->drawSimpleRect(rect, NULL, 1 << 0);
456f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
457f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    drawState->setTexture(0, NULL);
458f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
459f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
460f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.comnamespace {
461f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
462f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.comvoid clear(GrGpu* gpu,
463f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com           GrTexture* target,
464f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com           GrColor color) {
465f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrDrawState* drawState = gpu->drawState();
466f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrAssert(NULL != drawState);
467f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
468f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // zap entire target to specified color
469f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    drawState->setRenderTarget(target->asRenderTarget());
470f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    gpu->clear(NULL, color);
471f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
472f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
473f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com}
474f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com
4756d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com// get a texture to act as a temporary buffer for AA clip boolean operations
4766d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com// TODO: given the expense of createTexture we may want to just cache this too
4776623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.comvoid GrClipMaskManager::getTemp(const GrIRect& bounds,
478f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com                                GrAutoScratchTexture* temp) {
479f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    if (NULL != temp->texture()) {
4806d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com        // we've already allocated the temp texture
4816d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com        return;
4826d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com    }
4836d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
4846b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    const GrTextureDesc desc = {
4856b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit,
4866623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com        bounds.width(),
4876623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com        bounds.height(),
4886b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        kAlpha_8_GrPixelConfig,
4896b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        0           // samples
4906b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    };
4916b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
4922c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com    temp->set(this->getContext(), desc);
4936d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com}
4946d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
4956d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
496f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.comvoid GrClipMaskManager::setupCache(const GrClip& clipIn,
4976623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                                   const GrIRect& bounds) {
498f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    // Since we are setting up the cache we know the last lookup was a miss
499f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    // Free up the currently cached mask so it can be reused
500f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    fAACache.reset();
5016d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
502f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    const GrTextureDesc desc = {
503f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com        kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit,
5046623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com        bounds.width(),
5056623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com        bounds.height(),
506f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com        kAlpha_8_GrPixelConfig,
507f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com        0           // samples
508f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    };
509f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
510f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    fAACache.acquireMask(clipIn, desc, bounds);
511f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com}
512f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
5136b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
5146b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Shared preamble between gpu and SW-only AA clip mask creation paths.
5156b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Handles caching, determination of clip mask bound & allocation (if needed)
5166b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// of the result texture
5176b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Returns true if there is no more work to be done (i.e., we got a cache hit)
5186b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.combool GrClipMaskManager::clipMaskPreamble(GrGpu* gpu,
5196b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                         const GrClip& clipIn,
5206b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                         GrTexture** result,
5216623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                                         GrIRect *resultBounds) {
522f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrDrawState* origDrawState = gpu->drawState();
523f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrAssert(origDrawState->isClipState());
524f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
525f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrRenderTarget* rt = origDrawState->getRenderTarget();
526f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrAssert(NULL != rt);
527f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
528f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrRect rtRect;
529f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    rtRect.setLTRB(0, 0,
530f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                    GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
531f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
532f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // unlike the stencil path the alpha path is not bound to the size of the
533f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // render target - determine the minimum size required for the mask
534f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrRect bounds;
535f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
536f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    if (clipIn.hasConservativeBounds()) {
537f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        bounds = clipIn.getConservativeBounds();
538f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        if (!bounds.intersect(rtRect)) {
539f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // the mask will be empty in this case
540f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            GrAssert(false);
541f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            bounds.setEmpty();
542f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        }
543f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    } else {
544f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // still locked to the size of the render target
545f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        bounds = rtRect;
546f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
547f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
5486623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com    GrIRect intBounds;
5496623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com    bounds.roundOut(&intBounds);
550f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
551f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // need to outset a pixel since the standard bounding box computation
552f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // path doesn't leave any room for antialiasing (esp. w.r.t. rects)
5536623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com    intBounds.outset(1, 1);
554f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
555a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    // TODO: make sure we don't outset if bounds are still 0,0 @ min
556a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
5578fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com    if (fAACache.canReuse(clipIn,
5586623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                          intBounds.width(),
5596623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                          intBounds.height())) {
5608fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com        *result = fAACache.getLastMask();
5618fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com        fAACache.getLastBound(resultBounds);
5628fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com        return true;
5638fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com    }
5648fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com
5656623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com    this->setupCache(clipIn, intBounds);
566f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com
5676623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com    *resultBounds = intBounds;
5686b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    return false;
5696b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com}
570f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
5716b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
5726b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Create a 8-bit clip mask in alpha
5736b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.combool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu,
5746b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                            const GrClip& clipIn,
5756b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                            GrTexture** result,
5766623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                                            GrIRect *resultBounds) {
5776b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
578f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) {
5796b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        return true;
5806b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
581f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
582f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    GrTexture* accum = fAACache.getLastMask();
5836d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com    if (NULL == accum) {
584f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        fClipMaskInAlpha = false;
585f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com        fAACache.reset();
586f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        return false;
587f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
588f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
589f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
590f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrDrawState* drawState = gpu->drawState();
591f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
592f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrDrawTarget::AutoGeometryPush agp(gpu);
593f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
594f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    int count = clipIn.getElementCount();
595f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
5966b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
597f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // if we were able to trim down the size of the mask we need to
598f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // offset the paths & rects that will be used to compute it
599f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        GrMatrix m;
600f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6016623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com        m.setTranslate(SkIntToScalar(-resultBounds->fLeft),
6026623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                       SkIntToScalar(-resultBounds->fTop));
603f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6046d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com        drawState->setViewMatrix(m);
605f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
606f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
607f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    bool clearToInside;
608f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning
609f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    int start = process_initial_clip_elements(clipIn,
6106b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                              *resultBounds,
611f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                                              &clearToInside,
612f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                                              &startOp);
613f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6146d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com    clear(gpu, accum, clearToInside ? 0xffffffff : 0x00000000);
615f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
616f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    GrAutoScratchTexture temp;
6176b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
618f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // walk through each clip element and perform its set op
619f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    for (int c = start; c < count; ++c) {
620f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
621f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        SkRegion::Op op = (c == start) ? startOp : clipIn.getOp(c);
622f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
623f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        if (SkRegion::kReplace_Op == op) {
624f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // TODO: replace is actually a lot faster then intersection
625f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // for this path - refactor the stencil path so it can handle
626f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // replace ops and alter GrClip to allow them through
627f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
628f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // clear the accumulator and draw the new object directly into it
6296d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com            clear(gpu, accum, 0x00000000);
630f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6316b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            setup_boolean_blendcoeffs(drawState, op);
632f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            this->drawClipShape(gpu, accum, clipIn, c);
633f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
634f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        } else if (SkRegion::kReverseDifference_Op == op ||
635f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                   SkRegion::kIntersect_Op == op) {
636f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // there is no point in intersecting a screen filling rectangle.
637f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            if (SkRegion::kIntersect_Op == op &&
638f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                kRect_ClipType == clipIn.getElementType(c) &&
6396623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                contains(clipIn.getRect(c), *resultBounds)) {
640f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                continue;
641f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            }
642f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
643f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com            getTemp(*resultBounds, &temp);
644f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com            if (NULL == temp.texture()) {
6456d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com                fClipMaskInAlpha = false;
646f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com                fAACache.reset();
6476d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com                return false;
6486d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com            }
6496d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
650f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // clear the temp target & draw into it
651f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com            clear(gpu, temp.texture(), 0x00000000);
652f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6536b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
654f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com            this->drawClipShape(gpu, temp.texture(), clipIn, c);
655f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
656f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // TODO: rather than adding these two translations here
657f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // compute the bounding box needed to render the texture
658f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // into temp
6596b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
660f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                GrMatrix m;
661f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6626623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                m.setTranslate(SkIntToScalar(resultBounds->fLeft),
6636623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                               SkIntToScalar(resultBounds->fTop));
664f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
665f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                drawState->preConcatViewMatrix(m);
666f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            }
667f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
668f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // Now draw into the accumulator using the real operation
669f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // and the temp buffer as a texture
6706b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            setup_boolean_blendcoeffs(drawState, op);
671f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com            this->drawTexture(gpu, accum, temp.texture());
672f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6736b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
674f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                GrMatrix m;
675f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6766623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                m.setTranslate(SkIntToScalar(-resultBounds->fLeft),
6776623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                               SkIntToScalar(-resultBounds->fTop));
678f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
679f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                drawState->preConcatViewMatrix(m);
680f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            }
681f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
682f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        } else {
683f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // all the remaining ops can just be directly draw into
684f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // the accumulation buffer
6856b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            setup_boolean_blendcoeffs(drawState, op);
686f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            this->drawClipShape(gpu, accum, clipIn, c);
687f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        }
688f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
689f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
690a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    *result = accum;
6916d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
692f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    return true;
6931e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
6941e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
695f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
6961e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com// Create a 1-bit clip mask in the stencil buffer
6971e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.combool GrClipMaskManager::createStencilClipMask(GrGpu* gpu,
6981e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                              const GrClip& clipIn,
6991e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                              const GrRect& bounds,
7001e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                              ScissoringSettings* scissorSettings) {
7011e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7021e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrAssert(fClipMaskInStencil);
7031e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrDrawState* drawState = gpu->drawState();
7051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrAssert(drawState->isClipState());
7061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrRenderTarget* rt = drawState->getRenderTarget();
7081e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrAssert(NULL != rt);
7091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7101e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // TODO: dynamically attach a SB when needed.
7111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
7121e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    if (NULL == stencilBuffer) {
7131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        return false;
7141e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
7151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7161e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    if (stencilBuffer->mustRenderClip(clipIn, rt->width(), rt->height())) {
7171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7181e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        stencilBuffer->setLastClip(clipIn, rt->width(), rt->height());
7191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7201e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // we set the current clip to the bounds so that our recursive
7211e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // draws are scissored to them. We use the copy of the complex clip
7221e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // we just stashed on the SB to render from. We set it back after
7231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // we finish drawing it into the stencil.
7241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        const GrClip& clipCopy = stencilBuffer->getLastClip();
7251e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        gpu->setClip(GrClip(bounds));
7261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7271e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
7281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        drawState = gpu->drawState();
7291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        drawState->setRenderTarget(rt);
7301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        GrDrawTarget::AutoGeometryPush agp(gpu);
7311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7321e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        gpu->disableScissor();
7331e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#if !VISUALIZE_COMPLEX_CLIP
7341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
7351e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#endif
7361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        int count = clipCopy.getElementCount();
7381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        int clipBit = stencilBuffer->bits();
7391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        SkASSERT((clipBit <= 16) &&
7401e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    "Ganesh only handles 16b or smaller stencil buffers");
7411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        clipBit = (1 << (clipBit-1));
7421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7436623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com        GrIRect rtRect = GrIRect::MakeWH(rt->width(), rt->height());
7441e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        bool clearToInside;
7460f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com        SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning
7471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        int start = process_initial_clip_elements(clipCopy,
7481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                                    rtRect,
7491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                                    &clearToInside,
7501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                                    &startOp);
7511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7521e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        gpu->clearStencilClip(scissorSettings->fScissorRect, clearToInside);
7531e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // walk through each clip element and perform its set op
7551e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // with the existing clip.
7561e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        for (int c = start; c < count; ++c) {
7571e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            GrPathFill fill;
7581e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            bool fillInverted;
7591e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // enabled at bottom of loop
7601e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            drawState->disableState(GrGpu::kModifyStencilClip_StateBit);
7611e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7621e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            bool canRenderDirectToStencil; // can the clip element be drawn
7636b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                           // directly to the stencil buffer
7646b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                           // with a non-inverted fill rule
7656b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                           // without extra passes to
7666b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                           // resolve in/out status.
7671e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
768f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            SkRegion::Op op = (c == start) ? startOp : clipCopy.getOp(c);
769f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
7701e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            GrPathRenderer* pr = NULL;
7718d033a1b125886c62906d975b5cc28a382064526bsalomon@google.com            const SkPath* clipPath = NULL;
7721e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            if (kRect_ClipType == clipCopy.getElementType(c)) {
7731e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                canRenderDirectToStencil = true;
7741e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                fill = kEvenOdd_PathFill;
7751e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                fillInverted = false;
7761e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // there is no point in intersecting a screen filling
7771e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // rectangle.
778f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                if (SkRegion::kIntersect_Op == op &&
7796623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                    contains(clipCopy.getRect(c), rtRect)) {
7801e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    continue;
7811e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
7821e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            } else {
7831e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                fill = clipCopy.getPathFill(c);
7841e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                fillInverted = GrIsFillInverted(fill);
7851e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                fill = GrNonInvertedFill(fill);
7861e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                clipPath = &clipCopy.getPath(c);
7872c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com                pr = this->getContext()->getPathRenderer(*clipPath,
78872176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com                                                         fill, gpu, false,
78972176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com                                                         true);
7901e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (NULL == pr) {
7911e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    fClipMaskInStencil = false;
7921e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    gpu->setClip(clipCopy);     // restore to the original
7931e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    return false;
7941e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
7951e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                canRenderDirectToStencil =
7961e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    !pr->requiresStencilPass(*clipPath, fill, gpu);
7971e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
7981e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7991e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            int passes;
8001e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
8011e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8021e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            bool canDrawDirectToClip; // Given the renderer, the element,
8031e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                        // fill rule, and set operation can
8041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                        // we render the element directly to
8051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                        // stencil bit used for clipping.
8061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            canDrawDirectToClip =
8071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                GrStencilSettings::GetClipPasses(op,
8081e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                                    canRenderDirectToStencil,
8091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                                    clipBit,
8101e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                                    fillInverted,
8111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                                    &passes, stencilSettings);
8121e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // draw the element to the client stencil bits if necessary
8141e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            if (!canDrawDirectToClip) {
8151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
8161e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    kIncClamp_StencilOp,
8171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    kIncClamp_StencilOp,
8181e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    kAlways_StencilFunc,
8191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    0xffff,
8201e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    0x0000,
8211e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    0xffff);
8221e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                SET_RANDOM_COLOR
8231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (kRect_ClipType == clipCopy.getElementType(c)) {
8241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    *drawState->stencil() = gDrawToStencil;
8251e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0);
8261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
8271e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    if (canRenderDirectToStencil) {
8281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        *drawState->stencil() = gDrawToStencil;
8291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        pr->drawPath(*clipPath, fill, NULL, gpu, 0, false);
8301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    } else {
8311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        pr->drawPathToStencil(*clipPath, fill, gpu);
8321e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    }
8331e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
8341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
8351e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // now we modify the clip bit by rendering either the clip
8371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // element directly or a bounding rect of the entire clip.
8381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            drawState->enableState(GrGpu::kModifyStencilClip_StateBit);
8391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            for (int p = 0; p < passes; ++p) {
8401e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                *drawState->stencil() = stencilSettings[p];
8411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (canDrawDirectToClip) {
8421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    if (kRect_ClipType == clipCopy.getElementType(c)) {
8431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        SET_RANDOM_COLOR
8441e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0);
8451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    } else {
8461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        SET_RANDOM_COLOR
8471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        pr->drawPath(*clipPath, fill, NULL, gpu, 0, false);
8481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    }
8491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
8501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    SET_RANDOM_COLOR
8511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    gpu->drawSimpleRect(bounds, NULL, 0);
8521e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
8531e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
8541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        }
8551e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // restore clip
8561e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        gpu->setClip(clipCopy);
8571e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // recusive draws would have disabled this since they drew with
8581e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // the clip bounds as clip.
8591e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        fClipMaskInStencil = true;
8601e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
8611e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8621e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    return true;
8631e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
8641e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
865fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.comnamespace {
866fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
867fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.comGrPathFill invert_fill(GrPathFill fill) {
868fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    static const GrPathFill gInvertedFillTable[] = {
869fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        kInverseWinding_PathFill, // kWinding_PathFill
870fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        kInverseEvenOdd_PathFill, // kEvenOdd_PathFill
871fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        kWinding_PathFill,        // kInverseWinding_PathFill
872fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        kEvenOdd_PathFill,        // kInverseEvenOdd_PathFill
873fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        kHairLine_PathFill,       // kHairLine_PathFill
874fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    };
875fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    GR_STATIC_ASSERT(0 == kWinding_PathFill);
876fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    GR_STATIC_ASSERT(1 == kEvenOdd_PathFill);
877fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    GR_STATIC_ASSERT(2 == kInverseWinding_PathFill);
878fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    GR_STATIC_ASSERT(3 == kInverseEvenOdd_PathFill);
879fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    GR_STATIC_ASSERT(4 == kHairLine_PathFill);
880fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    GR_STATIC_ASSERT(5 == kPathFillCount);
881fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    return gInvertedFillTable[fill];
882fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com}
883fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
884fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com}
885fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
886f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
8876b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.combool GrClipMaskManager::createSoftwareClipMask(GrGpu* gpu,
8886b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                               const GrClip& clipIn,
8896b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                               GrTexture** result,
8906623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                                               GrIRect *resultBounds) {
8916b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
892f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) {
8936b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        return true;
8946b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
8956b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
896f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    GrTexture* accum = fAACache.getLastMask();
8976b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    if (NULL == accum) {
8986b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        fClipMaskInAlpha = false;
899f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com        fAACache.reset();
9006b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        return false;
9016b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
9026b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
9032c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com    GrSWMaskHelper helper(this->getContext());
9046b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
905fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    helper.init(*resultBounds, NULL, false);
906fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
907fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    int count = clipIn.getElementCount();
908fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
909fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    bool clearToInside;
910fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning
911fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    int start = process_initial_clip_elements(clipIn,
912fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                                              *resultBounds,
913fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                                              &clearToInside,
914fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                                              &startOp);
915fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
916fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    helper.clear(clearToInside ? SK_ColorWHITE : 0x00000000);
917fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
918fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    for (int i = start; i < count; ++i) {
919fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
920fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        SkRegion::Op op = (i == start) ? startOp : clipIn.getOp(i);
921fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
922fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        if (SkRegion::kIntersect_Op == op ||
923fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            SkRegion::kReverseDifference_Op == op) {
924fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // Intersect and reverse difference require modifying pixels
925fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // outside of the geometry that is being "drawn". In both cases
926fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // we erase all the pixels outside of the geometry but
927fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // leave the pixels inside the geometry alone. For reverse
928fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // difference we invert all the pixels before clearing the ones
929fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // outside the geometry.
930fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            if (SkRegion::kReverseDifference_Op == op) {
931fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                SkRect temp = SkRect::MakeLTRB(
932fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                                       SkIntToScalar(resultBounds->left()),
933fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                                       SkIntToScalar(resultBounds->top()),
934fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                                       SkIntToScalar(resultBounds->right()),
935fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                                       SkIntToScalar(resultBounds->bottom()));
936fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
937fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                // invert the entire scene
938fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                helper.draw(temp, SkRegion::kXOR_Op, false, SK_ColorWHITE);
939fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            }
940fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
941fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            if (kRect_ClipType == clipIn.getElementType(i)) {
942fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
943fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                // convert the rect to a path so we can invert the fill
944fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                SkPath temp;
945fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                temp.addRect(clipIn.getRect(i));
946fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
947fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                helper.draw(temp, SkRegion::kReplace_Op,
948fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                            kInverseEvenOdd_PathFill, clipIn.getDoAA(i),
949fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                            0x00000000);
950fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            } else {
951fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                GrAssert(kPath_ClipType == clipIn.getElementType(i));
952fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
953fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                helper.draw(clipIn.getPath(i),
954fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                            SkRegion::kReplace_Op,
955fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                            invert_fill(clipIn.getPathFill(i)),
956fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                            clipIn.getDoAA(i),
957fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                            0x00000000);
958fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            }
959fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
960fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            continue;
961fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        }
962fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
963fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        // The other ops (union, xor, diff) only affect pixels inside
964fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        // the geometry so they can just be drawn normally
9656b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        if (kRect_ClipType == clipIn.getElementType(i)) {
966fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
967fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            helper.draw(clipIn.getRect(i),
968fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                        op,
969fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                        clipIn.getDoAA(i), SK_ColorWHITE);
970fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
9716b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        } else {
9726b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            GrAssert(kPath_ClipType == clipIn.getElementType(i));
9736b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
974fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            helper.draw(clipIn.getPath(i),
975fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                        op,
976fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                        clipIn.getPathFill(i),
977fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                        clipIn.getDoAA(i), SK_ColorWHITE);
9786b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        }
9796b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
9806b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
981fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // Because we are using the scratch texture cache, "accum" may be
982fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // larger than expected and have some cruft in the areas we aren't using.
983fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // Clear it out.
984fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
985fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // TODO: need a simpler way to clear the texture - can we combine
986fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // the clear and the writePixels (inside toTexture)
987fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    GrDrawState* drawState = gpu->drawState();
988fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    GrAssert(NULL != drawState);
989fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    GrRenderTarget* temp = drawState->getRenderTarget();
990fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    clear(gpu, accum, 0x00000000);
991fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // can't leave the accum bound as a rendertarget
992fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    drawState->setRenderTarget(temp);
993fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
994fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    helper.toTexture(accum);
9956b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
9966b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    *result = accum;
9976b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
9986b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    return true;
9996b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com}
10006b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1001f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
1002f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.comvoid GrClipMaskManager::releaseResources() {
1003f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    fAACache.releaseResources();
10041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
1005