• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
24 static 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 
32 GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
33 GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
34 GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
35 GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
36 GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
37 GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
38 
gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op)39 static 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 
GrGLPathRendering(GrGpuGL * gpu)51 GrGLPathRendering::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 
~GrGLPathRendering()70 GrGLPathRendering::~GrGLPathRendering() {
71 }
72 
abandonGpuResources()73 void GrGLPathRendering::abandonGpuResources() {
74     fPathNameAllocator.reset(NULL);
75 }
76 
resetContext()77 void 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 
createPath(const SkPath & inPath,const SkStrokeRec & stroke)95 GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const SkStrokeRec& stroke) {
96     return SkNEW_ARGS(GrGLPath, (fGpu, inPath, stroke));
97 }
98 
createPathRange(GrPathRange::PathGenerator * pathGenerator,const SkStrokeRec & stroke)99 GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
100                                                 const SkStrokeRec& stroke) {
101     return SkNEW_ARGS(GrGLPathRange, (fGpu, pathGenerator, stroke));
102 }
103 
createGlyphs(const SkTypeface * typeface,const SkDescriptor * desc,const SkStrokeRec & stroke)104 GrPathRange* 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 
stencilPath(const GrPath * path,SkPath::FillType fill)155 void 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 
drawPath(const GrPath * path,SkPath::FillType fill)169 void 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 
drawPaths(const GrPathRange * pathRange,const uint32_t indices[],int count,const float transforms[],PathTransformType transformsType,SkPath::FillType fill)223 void 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 
enablePathTexGen(int unitIdx,PathTexGenComponents components,const GrGLfloat * coefficients)299 void 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 
enablePathTexGen(int unitIdx,PathTexGenComponents components,const SkMatrix & matrix)321 void 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 
flushPathTexGenSettings(int numUsedTexCoordSets)346 void 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 
setProgramPathFragmentInputTransform(GrGLuint program,GrGLint location,GrGLenum genMode,GrGLint components,const SkMatrix & matrix)369 void 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 
setProjectionMatrix(const SkMatrix & matrix,const SkISize & renderTargetSize,GrSurfaceOrigin renderTargetOrigin)395 void 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 
genPaths(GrGLsizei range)418 GrGLuint 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 
deletePaths(GrGLuint path,GrGLsizei range)444 void 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 
flushPathStencilSettings(SkPath::FillType fill)469 void 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 
stencilThenCoverFillPath(GrGLuint path,GrGLenum fillMode,GrGLuint mask,GrGLenum coverMode)484 inline 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 
stencilThenCoverStrokePath(GrGLuint path,GrGLint reference,GrGLuint mask,GrGLenum coverMode)494 inline 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 
stencilThenCoverFillPathInstanced(GrGLsizei numPaths,GrGLenum pathNameType,const GrGLvoid * paths,GrGLuint pathBase,GrGLenum fillMode,GrGLuint mask,GrGLenum coverMode,GrGLenum transformType,const GrGLfloat * transformValues)504 inline 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 
stencilThenCoverStrokePathInstanced(GrGLsizei numPaths,GrGLenum pathNameType,const GrGLvoid * paths,GrGLuint pathBase,GrGLint reference,GrGLuint mask,GrGLenum coverMode,GrGLenum transformType,const GrGLfloat * transformValues)519 inline 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