1/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gl/GrGLPathRendering.h"
9#include "gl/GrGLNameAllocator.h"
10#include "gl/GrGLUtil.h"
11#include "gl/GrGpuGL.h"
12
13#include "GrGLPath.h"
14#include "GrGLPathRange.h"
15#include "GrGLPathRendering.h"
16
17#include "SkStream.h"
18#include "SkTypeface.h"
19
20#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
21#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(fGpu->glInterface(), RET, X)
22
23
24static const GrGLenum gXformType2GLType[] = {
25    GR_GL_NONE,
26    GR_GL_TRANSLATE_X,
27    GR_GL_TRANSLATE_Y,
28    GR_GL_TRANSLATE_2D,
29    GR_GL_TRANSPOSE_AFFINE_2D
30};
31
32GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
33GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
34GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
35GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
36GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
37GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
38
39static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
40    switch (op) {
41        default:
42            SkFAIL("Unexpected path fill.");
43            /* fallthrough */;
44        case kIncClamp_StencilOp:
45            return GR_GL_COUNT_UP;
46        case kInvert_StencilOp:
47            return GR_GL_INVERT;
48    }
49}
50
51GrGLPathRendering::GrGLPathRendering(GrGpuGL* gpu)
52    : fGpu(gpu) {
53    const GrGLInterface* glInterface = gpu->glInterface();
54    fCaps.stencilThenCoverSupport =
55        NULL != glInterface->fFunctions.fStencilThenCoverFillPath &&
56        NULL != glInterface->fFunctions.fStencilThenCoverStrokePath &&
57        NULL != glInterface->fFunctions.fStencilThenCoverFillPathInstanced &&
58        NULL != glInterface->fFunctions.fStencilThenCoverStrokePathInstanced;
59    fCaps.fragmentInputGenSupport =
60        kGLES_GrGLStandard == glInterface->fStandard &&
61        NULL != glInterface->fFunctions.fProgramPathFragmentInputGen;
62    fCaps.glyphLoadingSupport =
63        NULL != glInterface->fFunctions.fPathMemoryGlyphIndexArray;
64
65    if (!fCaps.fragmentInputGenSupport) {
66        fHWPathTexGenSettings.reset(fGpu->glCaps().maxFixedFunctionTextureCoords());
67    }
68}
69
70GrGLPathRendering::~GrGLPathRendering() {
71}
72
73void GrGLPathRendering::abandonGpuResources() {
74    fPathNameAllocator.reset(NULL);
75}
76
77void GrGLPathRendering::resetContext() {
78    fHWProjectionMatrixState.invalidate();
79    // we don't use the model view matrix.
80    GrGLenum matrixMode =
81        fGpu->glStandard() == kGLES_GrGLStandard ? GR_GL_PATH_MODELVIEW : GR_GL_MODELVIEW;
82    GL_CALL(MatrixLoadIdentity(matrixMode));
83
84    if (!caps().fragmentInputGenSupport) {
85        for (int i = 0; i < fGpu->glCaps().maxFixedFunctionTextureCoords(); ++i) {
86            GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
87            fHWPathTexGenSettings[i].fMode = GR_GL_NONE;
88            fHWPathTexGenSettings[i].fNumComponents = 0;
89        }
90        fHWActivePathTexGenSets = 0;
91    }
92    fHWPathStencilSettings.invalidate();
93}
94
95GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const SkStrokeRec& stroke) {
96    return SkNEW_ARGS(GrGLPath, (fGpu, inPath, stroke));
97}
98
99GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
100                                                const SkStrokeRec& stroke) {
101    return SkNEW_ARGS(GrGLPathRange, (fGpu, pathGenerator, stroke));
102}
103
104GrPathRange* GrGLPathRendering::createGlyphs(const SkTypeface* typeface,
105                                             const SkDescriptor* desc,
106                                             const SkStrokeRec& stroke) {
107    if (NULL != desc || !caps().glyphLoadingSupport) {
108        return GrPathRendering::createGlyphs(typeface, desc, stroke);
109    }
110
111    if (NULL == typeface) {
112        typeface = SkTypeface::GetDefaultTypeface();
113        SkASSERT(NULL != typeface);
114    }
115
116    int faceIndex;
117    SkAutoTUnref<SkStream> fontStream(typeface->openStream(&faceIndex));
118
119    const size_t fontDataLength = fontStream->getLength();
120    if (0 == fontDataLength) {
121        return GrPathRendering::createGlyphs(typeface, NULL, stroke);
122    }
123
124    SkTArray<uint8_t> fontTempBuffer;
125    const void* fontData = fontStream->getMemoryBase();
126    if (NULL == fontData) {
127        // TODO: Find a more efficient way to pass the font data (e.g. open file descriptor).
128        fontTempBuffer.reset(fontDataLength);
129        fontStream->read(&fontTempBuffer.front(), fontDataLength);
130        fontData = &fontTempBuffer.front();
131    }
132
133    const size_t numPaths = typeface->countGlyphs();
134    const GrGLuint basePathID = this->genPaths(numPaths);
135    SkAutoTUnref<GrGLPath> templatePath(SkNEW_ARGS(GrGLPath, (fGpu, SkPath(), stroke)));
136
137    GrGLenum status;
138    GL_CALL_RET(status, PathMemoryGlyphIndexArray(basePathID, GR_GL_STANDARD_FONT_FORMAT,
139                                                  fontDataLength, fontData, faceIndex, 0,
140                                                  numPaths, templatePath->pathID(),
141                                                  SkPaint::kCanonicalTextSizeForPaths));
142
143    if (GR_GL_FONT_GLYPHS_AVAILABLE != status) {
144        this->deletePaths(basePathID, numPaths);
145        return GrPathRendering::createGlyphs(typeface, NULL, stroke);
146    }
147
148    // This is a crude approximation. We may want to consider giving this class
149    // a pseudo PathGenerator whose sole purpose is to track the approximate gpu
150    // memory size.
151    const size_t gpuMemorySize = fontDataLength / 4;
152    return SkNEW_ARGS(GrGLPathRange, (fGpu, basePathID, numPaths, gpuMemorySize, stroke));
153}
154
155void GrGLPathRendering::stencilPath(const GrPath* path, SkPath::FillType fill) {
156    GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
157    SkASSERT(fGpu->drawState()->getRenderTarget());
158    SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
159
160    this->flushPathStencilSettings(fill);
161    SkASSERT(!fHWPathStencilSettings.isTwoSided());
162
163    GrGLenum fillMode =
164        gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
165    GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
166    GL_CALL(StencilFillPath(id, fillMode, writeMask));
167}
168
169void GrGLPathRendering::drawPath(const GrPath* path, SkPath::FillType fill) {
170    GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
171    SkASSERT(fGpu->drawState()->getRenderTarget());
172    SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
173
174    this->flushPathStencilSettings(fill);
175    SkASSERT(!fHWPathStencilSettings.isTwoSided());
176
177    const SkStrokeRec& stroke = path->getStroke();
178
179    SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(fill);
180
181    GrGLenum fillMode =
182        gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
183    GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
184
185    if (nonInvertedFill == fill) {
186        if (stroke.needToApply()) {
187            if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
188                GL_CALL(StencilFillPath(id, fillMode, writeMask));
189            }
190            this->stencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX);
191        } else {
192            this->stencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX);
193        }
194    } else {
195        if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
196            GL_CALL(StencilFillPath(id, fillMode, writeMask));
197        }
198        if (stroke.needToApply()) {
199            GL_CALL(StencilStrokePath(id, 0xffff, writeMask));
200        }
201
202        GrDrawState* drawState = fGpu->drawState();
203        GrDrawState::AutoViewMatrixRestore avmr;
204        SkRect bounds = SkRect::MakeLTRB(0, 0,
205                                         SkIntToScalar(drawState->getRenderTarget()->width()),
206                                         SkIntToScalar(drawState->getRenderTarget()->height()));
207        SkMatrix vmi;
208        // mapRect through persp matrix may not be correct
209        if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
210            vmi.mapRect(&bounds);
211            // theoretically could set bloat = 0, instead leave it because of matrix inversion
212            // precision.
213            SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf;
214            bounds.outset(bloat, bloat);
215        } else {
216            avmr.setIdentity(drawState);
217        }
218
219        fGpu->drawSimpleRect(bounds);
220    }
221}
222
223void GrGLPathRendering::drawPaths(const GrPathRange* pathRange, const uint32_t indices[], int count,
224                                  const float transforms[], PathTransformType transformsType,
225                                  SkPath::FillType fill) {
226    SkASSERT(fGpu->caps()->pathRenderingSupport());
227    SkASSERT(fGpu->drawState()->getRenderTarget());
228    SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
229
230    GrGLuint baseID = static_cast<const GrGLPathRange*>(pathRange)->basePathID();
231
232    this->flushPathStencilSettings(fill);
233    SkASSERT(!fHWPathStencilSettings.isTwoSided());
234
235    const SkStrokeRec& stroke = pathRange->getStroke();
236
237    SkPath::FillType nonInvertedFill =
238        SkPath::ConvertToNonInverseFillType(fill);
239
240    GrGLenum fillMode =
241        gr_stencil_op_to_gl_path_rendering_fill_mode(
242            fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
243    GrGLint writeMask =
244        fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
245
246    if (nonInvertedFill == fill) {
247        if (stroke.needToApply()) {
248            if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
249                GL_CALL(StencilFillPathInstanced(
250                                count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
251                                writeMask, gXformType2GLType[transformsType],
252                                transforms));
253            }
254            this->stencilThenCoverStrokePathInstanced(
255                                count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff, writeMask,
256                                GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
257                                gXformType2GLType[transformsType], transforms);
258        } else {
259            this->stencilThenCoverFillPathInstanced(
260                                count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode, writeMask,
261                                GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
262                                gXformType2GLType[transformsType], transforms);
263        }
264    } else {
265        if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
266            GL_CALL(StencilFillPathInstanced(
267                                count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
268                                writeMask, gXformType2GLType[transformsType],
269                                transforms));
270        }
271        if (stroke.needToApply()) {
272            GL_CALL(StencilStrokePathInstanced(
273                                count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff,
274                                writeMask, gXformType2GLType[transformsType],
275                                transforms));
276        }
277
278        GrDrawState* drawState = fGpu->drawState();
279        GrDrawState::AutoViewMatrixRestore avmr;
280        SkRect bounds = SkRect::MakeLTRB(0, 0,
281                                         SkIntToScalar(drawState->getRenderTarget()->width()),
282                                         SkIntToScalar(drawState->getRenderTarget()->height()));
283        SkMatrix vmi;
284        // mapRect through persp matrix may not be correct
285        if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
286            vmi.mapRect(&bounds);
287            // theoretically could set bloat = 0, instead leave it because of matrix inversion
288            // precision.
289            SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf;
290            bounds.outset(bloat, bloat);
291        } else {
292            avmr.setIdentity(drawState);
293        }
294
295        fGpu->drawSimpleRect(bounds);
296    }
297}
298
299void GrGLPathRendering::enablePathTexGen(int unitIdx, PathTexGenComponents components,
300                                         const GrGLfloat* coefficients) {
301    SkASSERT(components >= kS_PathTexGenComponents &&
302             components <= kSTR_PathTexGenComponents);
303    SkASSERT(fGpu->glCaps().maxFixedFunctionTextureCoords() >= unitIdx);
304
305    if (GR_GL_OBJECT_LINEAR == fHWPathTexGenSettings[unitIdx].fMode &&
306        components == fHWPathTexGenSettings[unitIdx].fNumComponents &&
307        !memcmp(coefficients, fHWPathTexGenSettings[unitIdx].fCoefficients,
308                3 * components * sizeof(GrGLfloat))) {
309        return;
310    }
311
312    fGpu->setTextureUnit(unitIdx);
313
314    fHWPathTexGenSettings[unitIdx].fNumComponents = components;
315    GL_CALL(PathTexGen(GR_GL_TEXTURE0 + unitIdx, GR_GL_OBJECT_LINEAR, components, coefficients));
316
317    memcpy(fHWPathTexGenSettings[unitIdx].fCoefficients, coefficients,
318           3 * components * sizeof(GrGLfloat));
319}
320
321void GrGLPathRendering::enablePathTexGen(int unitIdx, PathTexGenComponents components,
322                                         const SkMatrix& matrix) {
323    GrGLfloat coefficients[3 * 3];
324    SkASSERT(components >= kS_PathTexGenComponents &&
325             components <= kSTR_PathTexGenComponents);
326
327    coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
328    coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
329    coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
330
331    if (components >= kST_PathTexGenComponents) {
332        coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
333        coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
334        coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
335    }
336
337    if (components >= kSTR_PathTexGenComponents) {
338        coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
339        coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
340        coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
341    }
342
343    this->enablePathTexGen(unitIdx, components, coefficients);
344}
345
346void GrGLPathRendering::flushPathTexGenSettings(int numUsedTexCoordSets) {
347    SkASSERT(fGpu->glCaps().maxFixedFunctionTextureCoords() >= numUsedTexCoordSets);
348
349    // Only write the inactive path tex gens, since active path tex gens were
350    // written when they were enabled.
351
352    SkDEBUGCODE(
353        for (int i = 0; i < numUsedTexCoordSets; i++) {
354            SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
355        }
356    );
357
358    for (int i = numUsedTexCoordSets; i < fHWActivePathTexGenSets; i++) {
359        SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
360
361        fGpu->setTextureUnit(i);
362        GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
363        fHWPathTexGenSettings[i].fNumComponents = 0;
364    }
365
366    fHWActivePathTexGenSets = numUsedTexCoordSets;
367}
368
369void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
370                                                             GrGLenum genMode, GrGLint components,
371                                                             const SkMatrix& matrix) {
372    SkASSERT(caps().fragmentInputGenSupport);
373    GrGLfloat coefficients[3 * 3];
374    SkASSERT(components >= 1 && components <= 3);
375
376    coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
377    coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
378    coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
379
380    if (components >= 2) {
381        coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
382        coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
383        coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
384    }
385
386    if (components >= 3) {
387        coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
388        coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
389        coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
390    }
391
392    GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
393}
394
395void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
396                                  const SkISize& renderTargetSize,
397                                  GrSurfaceOrigin renderTargetOrigin) {
398
399    SkASSERT(fGpu->glCaps().pathRenderingSupport());
400
401    if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
402        renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
403        matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
404        return;
405    }
406
407    fHWProjectionMatrixState.fViewMatrix = matrix;
408    fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
409    fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
410
411    GrGLfloat glMatrix[4 * 4];
412    fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
413     GrGLenum matrixMode =
414         fGpu->glStandard() == kGLES_GrGLStandard ? GR_GL_PATH_PROJECTION : GR_GL_PROJECTION;
415     GL_CALL(MatrixLoadf(matrixMode, glMatrix));
416}
417
418GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
419    if (range > 1) {
420        GrGLuint name;
421        GL_CALL_RET(name, GenPaths(range));
422        return name;
423    }
424
425    if (NULL == fPathNameAllocator.get()) {
426        static const int range = 65536;
427        GrGLuint firstName;
428        GL_CALL_RET(firstName, GenPaths(range));
429        fPathNameAllocator.reset(SkNEW_ARGS(GrGLNameAllocator, (firstName, firstName + range)));
430    }
431
432    // When allocating names one at a time, pull from a client-side pool of
433    // available names in order to save a round trip to the GL server.
434    GrGLuint name = fPathNameAllocator->allocateName();
435
436    if (0 == name) {
437        // Our reserved path names are all in use. Fall back on GenPaths.
438        GL_CALL_RET(name, GenPaths(1));
439    }
440
441    return name;
442}
443
444void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
445    if (range > 1) {
446        // It is not supported to delete names in ranges that were allocated
447        // individually using GrGLPathNameAllocator.
448        SkASSERT(NULL == fPathNameAllocator.get() ||
449                 path + range <= fPathNameAllocator->firstName() ||
450                 path >= fPathNameAllocator->endName());
451        GL_CALL(DeletePaths(path, range));
452        return;
453    }
454
455    if (NULL == fPathNameAllocator.get() ||
456        path < fPathNameAllocator->firstName() ||
457        path >= fPathNameAllocator->endName()) {
458        // If we aren't inside fPathNameAllocator's range then this name was
459        // generated by the GenPaths fallback (or else was never allocated).
460        GL_CALL(DeletePaths(path, 1));
461        return;
462    }
463
464    // Make the path empty to save memory, but don't free the name in the driver.
465    GL_CALL(PathCommands(path, 0, NULL, 0, GR_GL_FLOAT, NULL));
466    fPathNameAllocator->free(path);
467}
468
469void GrGLPathRendering::flushPathStencilSettings(SkPath::FillType fill) {
470    GrStencilSettings pathStencilSettings;
471    fGpu->getPathStencilSettingsForFillType(fill, &pathStencilSettings);
472    if (fHWPathStencilSettings != pathStencilSettings) {
473        // Just the func, ref, and mask is set here. The op and write mask are params to the call
474        // that draws the path to the SB (glStencilFillPath)
475        GrGLenum func =
476            GrToGLStencilFunc(pathStencilSettings.func(GrStencilSettings::kFront_Face));
477        GL_CALL(PathStencilFunc(func, pathStencilSettings.funcRef(GrStencilSettings::kFront_Face),
478                                pathStencilSettings.funcMask(GrStencilSettings::kFront_Face)));
479
480        fHWPathStencilSettings = pathStencilSettings;
481    }
482}
483
484inline void GrGLPathRendering::stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
485                                                     GrGLuint mask, GrGLenum coverMode) {
486    if (caps().stencilThenCoverSupport) {
487        GL_CALL(StencilThenCoverFillPath(path, fillMode, mask, coverMode));
488        return;
489    }
490    GL_CALL(StencilFillPath(path, fillMode, mask));
491    GL_CALL(CoverFillPath(path, coverMode));
492}
493
494inline void GrGLPathRendering::stencilThenCoverStrokePath(GrGLuint path, GrGLint reference,
495                                                       GrGLuint mask, GrGLenum coverMode) {
496    if (caps().stencilThenCoverSupport) {
497        GL_CALL(StencilThenCoverStrokePath(path, reference, mask, coverMode));
498        return;
499    }
500    GL_CALL(StencilStrokePath(path, reference, mask));
501    GL_CALL(CoverStrokePath(path, coverMode));
502}
503
504inline void GrGLPathRendering::stencilThenCoverFillPathInstanced(
505             GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
506             GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode,
507             GrGLenum transformType, const GrGLfloat *transformValues) {
508    if (caps().stencilThenCoverSupport) {
509        GL_CALL(StencilThenCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, fillMode,
510                                                  mask, coverMode, transformType, transformValues));
511        return;
512    }
513    GL_CALL(StencilFillPathInstanced(numPaths, pathNameType, paths, pathBase,
514                                     fillMode, mask, transformType, transformValues));
515    GL_CALL(CoverFillPathInstanced(numPaths, pathNameType, paths, pathBase,
516                                   coverMode, transformType, transformValues));
517}
518
519inline void GrGLPathRendering::stencilThenCoverStrokePathInstanced(
520        GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
521        GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode,
522        GrGLenum transformType, const GrGLfloat *transformValues) {
523    if (caps().stencilThenCoverSupport) {
524        GL_CALL(StencilThenCoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
525                                                    reference, mask, coverMode, transformType,
526                                                    transformValues));
527        return;
528    }
529
530    GL_CALL(StencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
531                                       reference, mask, transformType, transformValues));
532    GL_CALL(CoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
533                                     coverMode, transformType, transformValues));
534}
535