15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright 2012 Google Inc.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * found in the LICENSE file.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "GrGLPath.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "GrGLPathRendering.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "GrGpuGL.h"
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline GrGLubyte verb_to_gl_path_cmd(SkPath::Verb verb) {
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    static const GrGLubyte gTable[] = {
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GR_GL_MOVE_TO,
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GR_GL_LINE_TO,
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GR_GL_QUADRATIC_CURVE_TO,
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        0xFF, // conic
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        GR_GL_CUBIC_CURVE_TO,
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        GR_GL_CLOSE_PATH,
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    };
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GR_STATIC_ASSERT(0 == SkPath::kMove_Verb);
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GR_STATIC_ASSERT(1 == SkPath::kLine_Verb);
256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb);
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb);
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GR_STATIC_ASSERT(5 == SkPath::kClose_Verb);
286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SkASSERT(verb >= 0 && (size_t)verb < SK_ARRAY_COUNT(gTable));
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return gTable[verb];
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SK_DEBUG
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline int num_pts(SkPath::Verb verb) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const int gTable[] = {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        1, // move
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        1, // line
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        2, // quad
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        2, // conic
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        3, // cubic
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        0, // close
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    };
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    GR_STATIC_ASSERT(0 == SkPath::kMove_Verb);
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GR_STATIC_ASSERT(1 == SkPath::kLine_Verb);
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb);
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GR_STATIC_ASSERT(5 == SkPath::kClose_Verb);
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SkASSERT(verb >= 0 && (size_t)verb < SK_ARRAY_COUNT(gTable));
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return gTable[verb];
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)inline GrGLenum join_to_gl_join(SkPaint::Join join) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static GrGLenum gSkJoinsToGrGLJoins[] = {
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        GR_GL_MITER_REVERT,
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        GR_GL_ROUND,
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        GR_GL_BEVEL
591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    };
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return gSkJoinsToGrGLJoins[join];
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GR_STATIC_ASSERT(0 == SkPaint::kMiter_Join);
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    GR_STATIC_ASSERT(1 == SkPaint::kRound_Join);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GR_STATIC_ASSERT(2 == SkPaint::kBevel_Join);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gSkJoinsToGrGLJoins) == SkPaint::kJoinCount);
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)inline GrGLenum cap_to_gl_cap(SkPaint::Cap cap) {
68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    static GrGLenum gSkCapsToGrGLCaps[] = {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GR_GL_FLAT,
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GR_GL_ROUND,
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        GR_GL_SQUARE
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    };
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return gSkCapsToGrGLCaps[cap];
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    GR_STATIC_ASSERT(0 == SkPaint::kButt_Cap);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GR_STATIC_ASSERT(1 == SkPaint::kRound_Cap);
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GR_STATIC_ASSERT(2 == SkPaint::kSquare_Cap);
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gSkCapsToGrGLCaps) == SkPaint::kCapCount);
78558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
82010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)static const bool kIsWrapped = false; // The constructor creates the GL path object.
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void GrGLPath::InitPathObject(GrGpuGL* gpu,
856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                              GrGLuint pathID,
866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                              const SkPath& skPath,
876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                              const SkStrokeRec& stroke) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!skPath.isEmpty()) {
897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        SkSTArray<16, GrGLubyte, true> pathCommands;
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        SkSTArray<16, SkPoint, true> pathPoints;
917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        int verbCnt = skPath.countVerbs();
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        int pointCnt = skPath.countPoints();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pathCommands.resize_back(verbCnt);
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        pathPoints.resize_back(pointCnt);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO: Direct access to path points since we could pass them on directly.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        skPath.getPoints(&pathPoints[0], pointCnt);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        skPath.getVerbs(&pathCommands[0], verbCnt);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkDEBUGCODE(int numPts = 0);
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        for (int i = 0; i < verbCnt; ++i) {
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]);
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            pathCommands[i] = verb_to_gl_path_cmd(v);
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            SkDEBUGCODE(numPts += num_pts(v));
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkASSERT(pathPoints.count() == numPts);
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GR_GL_CALL(gpu->glInterface(),
110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                   PathCommands(pathID, verbCnt, &pathCommands[0],
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                2 * pointCnt, GR_GL_FLOAT, &pathPoints[0]));
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
113558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, NULL, 0, GR_GL_FLOAT, NULL));
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (stroke.needToApply()) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkASSERT(!stroke.isHairlineStyle());
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GR_GL_CALL(gpu->glInterface(),
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GR_GL_CALL(gpu->glInterface(),
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter())));
122        GrGLenum join = join_to_gl_join(stroke.getJoin());
123        GR_GL_CALL(gpu->glInterface(),
124            PathParameteri(pathID, GR_GL_PATH_JOIN_STYLE, join));
125        GrGLenum cap = cap_to_gl_cap(stroke.getCap());
126        GR_GL_CALL(gpu->glInterface(),
127            PathParameteri(pathID, GR_GL_PATH_INITIAL_END_CAP, cap));
128        GR_GL_CALL(gpu->glInterface(),
129            PathParameteri(pathID, GR_GL_PATH_TERMINAL_END_CAP, cap));
130    }
131}
132
133GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path, const SkStrokeRec& stroke)
134    : INHERITED(gpu, kIsWrapped, path, stroke),
135      fPathID(gpu->glPathRendering()->genPaths(1)) {
136
137    InitPathObject(gpu, fPathID, fSkPath, stroke);
138
139    if (stroke.needToApply()) {
140        // FIXME: try to account for stroking, without rasterizing the stroke.
141        fBounds.outset(stroke.getWidth(), stroke.getWidth());
142    }
143    this->registerWithCache();
144}
145
146GrGLPath::~GrGLPath() {
147    this->release();
148}
149
150void GrGLPath::onRelease() {
151    if (0 != fPathID && !this->isWrapped()) {
152        static_cast<GrGpuGL*>(this->getGpu())->glPathRendering()->deletePaths(fPathID, 1);
153        fPathID = 0;
154    }
155
156    INHERITED::onRelease();
157}
158
159void GrGLPath::onAbandon() {
160    fPathID = 0;
161
162    INHERITED::onAbandon();
163}
164