GrSoftwarePathRenderer.cpp revision 366f1c6a09f63c76e78145cb08028f66062f31fd
1f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com
2f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com/*
3f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com * Copyright 2012 Google Inc.
4f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com *
5f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com * Use of this source code is governed by a BSD-style license that can be
6f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com * found in the LICENSE file.
7f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com */
8f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com
9f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com#include "GrSoftwarePathRenderer.h"
10ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com#include "GrContext.h"
1158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com#include "GrSWMaskHelper.h"
12f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com
13ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
14f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.combool GrSoftwarePathRenderer::canDrawPath(const SkPath& path,
15f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com                                         GrPathFill fill,
16f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com                                         const GrDrawTarget* target,
17f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com                                         bool antiAlias) const {
18ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    if (!antiAlias || NULL == fContext) {
19ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        // TODO: We could allow the SW path to also handle non-AA paths but
20ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        // this would mean that GrDefaultPathRenderer would never be called
21ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        // (since it appears after the SW renderer in the path renderer
22ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        // chain). Some testing would need to be done r.e. performance
23ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        // and consistency of the resulting images before removing
24ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        // the "!antiAlias" clause from the above test
25f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com        return false;
26f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com    }
27f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com
28ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    return true;
29ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com}
30ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com
31ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.comnamespace {
32ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com
33ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
34ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com// gets device coord bounds of path (not considering the fill) and clip. The
35ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com// path bounds will be a subset of the clip bounds. returns false if
36ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com// path bounds would be empty.
37ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.combool get_path_and_clip_bounds(const GrDrawTarget* target,
38ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                              const SkPath& path,
39366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com                              const GrMatrix& matrix,
40ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                              GrIRect* pathBounds,
41ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                              GrIRect* clipBounds) {
42ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    // compute bounds as intersection of rt size, clip, and path
43ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
44ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    if (NULL == rt) {
45ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        return false;
46ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    }
47ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
48ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    const GrClip& clip = target->getClip();
49ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    if (clip.hasConservativeBounds()) {
50ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        clip.getConservativeBounds().roundOut(clipBounds);
51ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        if (!pathBounds->intersect(*clipBounds)) {
52ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com            return false;
53ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        }
54ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    } else {
55ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        // pathBounds is currently the rt extent, set clip bounds to that rect.
56ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        *clipBounds = *pathBounds;
57ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    }
58366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    if (!path.getBounds().isEmpty()) {
59366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com        GrRect pathSBounds;
60366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com        matrix.mapRect(&pathSBounds, path.getBounds());
61ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        GrIRect pathIBounds;
62ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        pathSBounds.roundOut(&pathIBounds);
63ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        if (!pathBounds->intersect(pathIBounds)) {
64276c1fabc22d4980c2ed8fe879f6510289b87cdebsalomon@google.com            // set the correct path bounds, as this would be used later.
65276c1fabc22d4980c2ed8fe879f6510289b87cdebsalomon@google.com            *pathBounds = pathIBounds;
66ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com            return false;
67ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        }
68ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    } else {
69276c1fabc22d4980c2ed8fe879f6510289b87cdebsalomon@google.com        *pathBounds = GrIRect::EmptyIRect();
70ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        return false;
71ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    }
72ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    return true;
73ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com}
74ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com
75ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
76ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.comvoid draw_around_inv_path(GrDrawTarget* target,
77ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                          GrDrawState::StageMask stageMask,
78ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                          const GrIRect& clipBounds,
79ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                          const GrIRect& pathBounds) {
80ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
81ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    GrRect rect;
82ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    if (clipBounds.fTop < pathBounds.fTop) {
83ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        rect.iset(clipBounds.fLeft, clipBounds.fTop,
84ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                    clipBounds.fRight, pathBounds.fTop);
85ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        target->drawSimpleRect(rect, NULL, stageMask);
86ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    }
87ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    if (clipBounds.fLeft < pathBounds.fLeft) {
88ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        rect.iset(clipBounds.fLeft, pathBounds.fTop,
89ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                    pathBounds.fLeft, pathBounds.fBottom);
90ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        target->drawSimpleRect(rect, NULL, stageMask);
91ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    }
92ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    if (clipBounds.fRight > pathBounds.fRight) {
93ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        rect.iset(pathBounds.fRight, pathBounds.fTop,
94ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                    clipBounds.fRight, pathBounds.fBottom);
95ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        target->drawSimpleRect(rect, NULL, stageMask);
96ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    }
97ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    if (clipBounds.fBottom > pathBounds.fBottom) {
98ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        rect.iset(clipBounds.fLeft, pathBounds.fBottom,
99ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                    clipBounds.fRight, clipBounds.fBottom);
100ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        target->drawSimpleRect(rect, NULL, stageMask);
101ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    }
102f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com}
103f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com
104ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com}
105ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com
106ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
107ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com// return true on success; false on failure
108f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.combool GrSoftwarePathRenderer::onDrawPath(const SkPath& path,
109f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com                                        GrPathFill fill,
110f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com                                        const GrVec* translate,
111f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com                                        GrDrawTarget* target,
112f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com                                        GrDrawState::StageMask stageMask,
113f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com                                        bool antiAlias) {
114f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com
115ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    if (NULL == fContext) {
116ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        return false;
117ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    }
118ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com
119366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    GrDrawState* drawState = target->drawState();
120366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com
121366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    GrMatrix vm = drawState->getViewMatrix();
122366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    if (NULL != translate) {
123366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com        vm.postTranslate(translate->fX, translate->fY);
124366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    }
125366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com
126ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    GrAutoScratchTexture ast;
127ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    GrIRect pathBounds, clipBounds;
128366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    if (!get_path_and_clip_bounds(target, path, vm,
129ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                                  &pathBounds, &clipBounds)) {
130276c1fabc22d4980c2ed8fe879f6510289b87cdebsalomon@google.com        if (GrIsFillInverted(fill)) {
131276c1fabc22d4980c2ed8fe879f6510289b87cdebsalomon@google.com            draw_around_inv_path(target, stageMask,
132276c1fabc22d4980c2ed8fe879f6510289b87cdebsalomon@google.com                                 clipBounds, pathBounds);
133276c1fabc22d4980c2ed8fe879f6510289b87cdebsalomon@google.com        }
134276c1fabc22d4980c2ed8fe879f6510289b87cdebsalomon@google.com        return true;
135ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    }
136366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com
137366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    if (GrSWMaskHelper::DrawToTexture(fContext, path, pathBounds, fill,
138366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com                                      &ast, antiAlias, &vm)) {
13915c0fea699b25343fe6f49668a5632866e1a0306robertphillips@google.com        SkAutoTUnref<GrTexture> texture(ast.detach());
140ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        GrAssert(NULL != texture);
141ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
142ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        enum {
1437ff2e371859982cad995f9d2a8cbdbb8601fc780robertphillips@google.com            // the SW path renderer shares this stage with glyph
1447ff2e371859982cad995f9d2a8cbdbb8601fc780robertphillips@google.com            // rendering (kGlyphMaskStage in GrBatchedTextContext)
1457ff2e371859982cad995f9d2a8cbdbb8601fc780robertphillips@google.com            kPathMaskStage = GrPaint::kTotalStages,
146ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        };
147366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com        GrAssert(NULL == drawState->getTexture(kPathMaskStage));
148366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com        drawState->setTexture(kPathMaskStage, texture);
149366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com        drawState->sampler(kPathMaskStage)->reset();
150ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        GrScalar w = GrIntToScalar(pathBounds.width());
151ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        GrScalar h = GrIntToScalar(pathBounds.height());
152ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        GrRect maskRect = GrRect::MakeWH(w / texture->width(),
153ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                                         h / texture->height());
15415c0fea699b25343fe6f49668a5632866e1a0306robertphillips@google.com
155ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
156ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        srcRects[kPathMaskStage] = &maskRect;
157ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        stageMask |= 1 << kPathMaskStage;
158ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        GrRect dstRect = GrRect::MakeLTRB(
159ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                              SK_Scalar1* pathBounds.fLeft,
160ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                              SK_Scalar1* pathBounds.fTop,
161ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                              SK_Scalar1* pathBounds.fRight,
162ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                              SK_Scalar1* pathBounds.fBottom);
163ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
164366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com        drawState->setTexture(kPathMaskStage, NULL);
165ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        if (GrIsFillInverted(fill)) {
166ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com            draw_around_inv_path(target, stageMask,
167ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com                                 clipBounds, pathBounds);
168ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        }
169ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com        return true;
170ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com    }
171ed4155d610442b75e906a3489c984394c34b5ff9robertphillips@google.com
172f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com    return false;
173f4c2c527dd3cab979621fdfbc07eb22fee103472robertphillips@google.com}
174