blob: 81d47c4722591e96a5e9253785639c63a66761c5 [file] [log] [blame]
cdaltonc7103a12014-08-11 14:05:05 -07001/*
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"
cdaltonc7103a12014-08-11 14:05:05 -07009#include "gl/GrGLNameAllocator.h"
10#include "gl/GrGLUtil.h"
kkinnunenccdaa042014-08-20 01:36:23 -070011#include "gl/GrGpuGL.h"
cdaltonc7103a12014-08-11 14:05:05 -070012
kkinnunenccdaa042014-08-20 01:36:23 -070013#include "GrGLPath.h"
14#include "GrGLPathRange.h"
15#include "GrGLPathRendering.h"
16
17#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
18#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(fGpu->glInterface(), RET, X)
19
20
21static const GrGLenum gXformType2GLType[] = {
22 GR_GL_NONE,
23 GR_GL_TRANSLATE_X,
24 GR_GL_TRANSLATE_Y,
25 GR_GL_TRANSLATE_2D,
26 GR_GL_TRANSPOSE_AFFINE_2D
27};
28
29GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
30GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
31GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
32GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
33GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
34GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
35
36static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
37 switch (op) {
38 default:
39 SkFAIL("Unexpected path fill.");
40 /* fallthrough */;
41 case kIncClamp_StencilOp:
42 return GR_GL_COUNT_UP;
43 case kInvert_StencilOp:
44 return GR_GL_INVERT;
45 }
46}
cdaltonc7103a12014-08-11 14:05:05 -070047
kkinnunenccdaa042014-08-20 01:36:23 -070048GrGLPathRendering::GrGLPathRendering(GrGpuGL* gpu)
49 : fGpu(gpu) {
kkinnunen5b653572014-08-20 04:13:27 -070050 const GrGLInterface* glInterface = gpu->glInterface();
51 fCaps.stencilThenCoverSupport =
cdalton149b3ec2014-09-17 09:19:18 -070052 NULL != glInterface->fFunctions.fStencilThenCoverFillPath &&
53 NULL != glInterface->fFunctions.fStencilThenCoverStrokePath &&
54 NULL != glInterface->fFunctions.fStencilThenCoverFillPathInstanced &&
55 NULL != glInterface->fFunctions.fStencilThenCoverStrokePathInstanced;
kkinnunen5b653572014-08-20 04:13:27 -070056 fCaps.fragmentInputGenSupport =
kkinnunenec56e452014-08-25 22:21:16 -070057 kGLES_GrGLStandard == glInterface->fStandard &&
cdalton149b3ec2014-09-17 09:19:18 -070058 NULL != glInterface->fFunctions.fProgramPathFragmentInputGen;
59 fCaps.glyphLoadingSupport =
60 NULL != glInterface->fFunctions.fPathMemoryGlyphIndexArray;
kkinnunenec56e452014-08-25 22:21:16 -070061
62 if (!fCaps.fragmentInputGenSupport) {
63 fHWPathTexGenSettings.reset(fGpu->glCaps().maxFixedFunctionTextureCoords());
64 }
cdaltonc7103a12014-08-11 14:05:05 -070065}
66
67GrGLPathRendering::~GrGLPathRendering() {
68}
69
70void GrGLPathRendering::abandonGpuResources() {
71 fPathNameAllocator.reset(NULL);
72}
73
kkinnunenccdaa042014-08-20 01:36:23 -070074void GrGLPathRendering::resetContext() {
75 fHWProjectionMatrixState.invalidate();
76 // we don't use the model view matrix.
kkinnunenec56e452014-08-25 22:21:16 -070077 GrGLenum matrixMode =
78 fGpu->glStandard() == kGLES_GrGLStandard ? GR_GL_PATH_MODELVIEW : GR_GL_MODELVIEW;
79 GL_CALL(MatrixLoadIdentity(matrixMode));
kkinnunenccdaa042014-08-20 01:36:23 -070080
kkinnunenec56e452014-08-25 22:21:16 -070081 if (!caps().fragmentInputGenSupport) {
82 for (int i = 0; i < fGpu->glCaps().maxFixedFunctionTextureCoords(); ++i) {
83 GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
84 fHWPathTexGenSettings[i].fMode = GR_GL_NONE;
85 fHWPathTexGenSettings[i].fNumComponents = 0;
86 }
87 fHWActivePathTexGenSets = 0;
kkinnunenccdaa042014-08-20 01:36:23 -070088 }
kkinnunenccdaa042014-08-20 01:36:23 -070089 fHWPathStencilSettings.invalidate();
90}
91
92GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const SkStrokeRec& stroke) {
93 return SkNEW_ARGS(GrGLPath, (fGpu, inPath, stroke));
94}
95
96GrPathRange* GrGLPathRendering::createPathRange(size_t size, const SkStrokeRec& stroke) {
97 return SkNEW_ARGS(GrGLPathRange, (fGpu, size, stroke));
98}
99
kkinnunen5b653572014-08-20 04:13:27 -0700100void GrGLPathRendering::stencilPath(const GrPath* path, SkPath::FillType fill) {
101 GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
bsalomon49f085d2014-09-05 13:34:00 -0700102 SkASSERT(fGpu->drawState()->getRenderTarget());
103 SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
kkinnunen5b653572014-08-20 04:13:27 -0700104
105 this->flushPathStencilSettings(fill);
106 SkASSERT(!fHWPathStencilSettings.isTwoSided());
107
108 GrGLenum fillMode =
109 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
110 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
111 GL_CALL(StencilFillPath(id, fillMode, writeMask));
112}
113
114void GrGLPathRendering::drawPath(const GrPath* path, SkPath::FillType fill) {
115 GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
bsalomon49f085d2014-09-05 13:34:00 -0700116 SkASSERT(fGpu->drawState()->getRenderTarget());
117 SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
kkinnunen5b653572014-08-20 04:13:27 -0700118
119 this->flushPathStencilSettings(fill);
120 SkASSERT(!fHWPathStencilSettings.isTwoSided());
121
122 const SkStrokeRec& stroke = path->getStroke();
123
124 SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(fill);
125
126 GrGLenum fillMode =
127 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
128 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
129
130 if (nonInvertedFill == fill) {
131 if (stroke.needToApply()) {
132 if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
133 GL_CALL(StencilFillPath(id, fillMode, writeMask));
134 }
135 this->stencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX);
136 } else {
137 this->stencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX);
138 }
139 } else {
140 if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
141 GL_CALL(StencilFillPath(id, fillMode, writeMask));
142 }
143 if (stroke.needToApply()) {
144 GL_CALL(StencilStrokePath(id, 0xffff, writeMask));
145 }
146
147 GrDrawState* drawState = fGpu->drawState();
148 GrDrawState::AutoViewMatrixRestore avmr;
149 SkRect bounds = SkRect::MakeLTRB(0, 0,
150 SkIntToScalar(drawState->getRenderTarget()->width()),
151 SkIntToScalar(drawState->getRenderTarget()->height()));
152 SkMatrix vmi;
153 // mapRect through persp matrix may not be correct
154 if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
155 vmi.mapRect(&bounds);
156 // theoretically could set bloat = 0, instead leave it because of matrix inversion
157 // precision.
158 SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf;
159 bounds.outset(bloat, bloat);
160 } else {
161 avmr.setIdentity(drawState);
162 }
163
164 fGpu->drawSimpleRect(bounds);
165 }
166}
167
168void GrGLPathRendering::drawPaths(const GrPathRange* pathRange, const uint32_t indices[], int count,
169 const float transforms[], PathTransformType transformsType,
170 SkPath::FillType fill) {
171 SkASSERT(fGpu->caps()->pathRenderingSupport());
bsalomon49f085d2014-09-05 13:34:00 -0700172 SkASSERT(fGpu->drawState()->getRenderTarget());
173 SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
kkinnunen5b653572014-08-20 04:13:27 -0700174
175 GrGLuint baseID = static_cast<const GrGLPathRange*>(pathRange)->basePathID();
176
177 this->flushPathStencilSettings(fill);
178 SkASSERT(!fHWPathStencilSettings.isTwoSided());
179
180 const SkStrokeRec& stroke = pathRange->getStroke();
181
182 SkPath::FillType nonInvertedFill =
183 SkPath::ConvertToNonInverseFillType(fill);
184
185 GrGLenum fillMode =
186 gr_stencil_op_to_gl_path_rendering_fill_mode(
187 fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
188 GrGLint writeMask =
189 fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
190
191 if (nonInvertedFill == fill) {
192 if (stroke.needToApply()) {
193 if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
194 GL_CALL(StencilFillPathInstanced(
195 count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
196 writeMask, gXformType2GLType[transformsType],
197 transforms));
198 }
199 this->stencilThenCoverStrokePathInstanced(
200 count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff, writeMask,
201 GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
202 gXformType2GLType[transformsType], transforms);
203 } else {
204 this->stencilThenCoverFillPathInstanced(
205 count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode, writeMask,
206 GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
207 gXformType2GLType[transformsType], transforms);
208 }
209 } else {
210 if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
211 GL_CALL(StencilFillPathInstanced(
212 count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
213 writeMask, gXformType2GLType[transformsType],
214 transforms));
215 }
216 if (stroke.needToApply()) {
217 GL_CALL(StencilStrokePathInstanced(
218 count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff,
219 writeMask, gXformType2GLType[transformsType],
220 transforms));
221 }
222
223 GrDrawState* drawState = fGpu->drawState();
224 GrDrawState::AutoViewMatrixRestore avmr;
225 SkRect bounds = SkRect::MakeLTRB(0, 0,
226 SkIntToScalar(drawState->getRenderTarget()->width()),
227 SkIntToScalar(drawState->getRenderTarget()->height()));
228 SkMatrix vmi;
229 // mapRect through persp matrix may not be correct
230 if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
231 vmi.mapRect(&bounds);
232 // theoretically could set bloat = 0, instead leave it because of matrix inversion
233 // precision.
234 SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf;
235 bounds.outset(bloat, bloat);
236 } else {
237 avmr.setIdentity(drawState);
238 }
239
240 fGpu->drawSimpleRect(bounds);
241 }
242}
243
kkinnunenccdaa042014-08-20 01:36:23 -0700244void GrGLPathRendering::enablePathTexGen(int unitIdx, PathTexGenComponents components,
245 const GrGLfloat* coefficients) {
246 SkASSERT(components >= kS_PathTexGenComponents &&
247 components <= kSTR_PathTexGenComponents);
248 SkASSERT(fGpu->glCaps().maxFixedFunctionTextureCoords() >= unitIdx);
249
250 if (GR_GL_OBJECT_LINEAR == fHWPathTexGenSettings[unitIdx].fMode &&
251 components == fHWPathTexGenSettings[unitIdx].fNumComponents &&
252 !memcmp(coefficients, fHWPathTexGenSettings[unitIdx].fCoefficients,
253 3 * components * sizeof(GrGLfloat))) {
254 return;
255 }
256
257 fGpu->setTextureUnit(unitIdx);
258
259 fHWPathTexGenSettings[unitIdx].fNumComponents = components;
kkinnunen5b653572014-08-20 04:13:27 -0700260 GL_CALL(PathTexGen(GR_GL_TEXTURE0 + unitIdx, GR_GL_OBJECT_LINEAR, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700261
262 memcpy(fHWPathTexGenSettings[unitIdx].fCoefficients, coefficients,
263 3 * components * sizeof(GrGLfloat));
264}
265
266void GrGLPathRendering::enablePathTexGen(int unitIdx, PathTexGenComponents components,
267 const SkMatrix& matrix) {
268 GrGLfloat coefficients[3 * 3];
269 SkASSERT(components >= kS_PathTexGenComponents &&
270 components <= kSTR_PathTexGenComponents);
271
272 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
273 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
274 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
275
276 if (components >= kST_PathTexGenComponents) {
277 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
278 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
279 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
280 }
281
282 if (components >= kSTR_PathTexGenComponents) {
283 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
284 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
285 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
286 }
287
288 this->enablePathTexGen(unitIdx, components, coefficients);
289}
290
291void GrGLPathRendering::flushPathTexGenSettings(int numUsedTexCoordSets) {
292 SkASSERT(fGpu->glCaps().maxFixedFunctionTextureCoords() >= numUsedTexCoordSets);
293
294 // Only write the inactive path tex gens, since active path tex gens were
295 // written when they were enabled.
296
297 SkDEBUGCODE(
298 for (int i = 0; i < numUsedTexCoordSets; i++) {
299 SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
300 }
301 );
302
303 for (int i = numUsedTexCoordSets; i < fHWActivePathTexGenSets; i++) {
304 SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
305
306 fGpu->setTextureUnit(i);
307 GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
308 fHWPathTexGenSettings[i].fNumComponents = 0;
309 }
310
311 fHWActivePathTexGenSets = numUsedTexCoordSets;
312}
313
kkinnunen5b653572014-08-20 04:13:27 -0700314void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
315 GrGLenum genMode, GrGLint components,
316 const SkMatrix& matrix) {
317 SkASSERT(caps().fragmentInputGenSupport);
318 GrGLfloat coefficients[3 * 3];
319 SkASSERT(components >= 1 && components <= 3);
kkinnunenccdaa042014-08-20 01:36:23 -0700320
kkinnunen5b653572014-08-20 04:13:27 -0700321 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
322 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
323 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
kkinnunenccdaa042014-08-20 01:36:23 -0700324
kkinnunen5b653572014-08-20 04:13:27 -0700325 if (components >= 2) {
326 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
327 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
328 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
kkinnunenccdaa042014-08-20 01:36:23 -0700329 }
kkinnunenccdaa042014-08-20 01:36:23 -0700330
kkinnunen5b653572014-08-20 04:13:27 -0700331 if (components >= 3) {
332 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
333 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
334 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
kkinnunenccdaa042014-08-20 01:36:23 -0700335 }
kkinnunenccdaa042014-08-20 01:36:23 -0700336
kkinnunen5b653572014-08-20 04:13:27 -0700337 GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700338}
339
340void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
341 const SkISize& renderTargetSize,
342 GrSurfaceOrigin renderTargetOrigin) {
343
344 SkASSERT(fGpu->glCaps().pathRenderingSupport());
345
346 if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
347 renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
348 matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
349 return;
350 }
351
352 fHWProjectionMatrixState.fViewMatrix = matrix;
353 fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
354 fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
355
356 GrGLfloat glMatrix[4 * 4];
357 fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
kkinnunenec56e452014-08-25 22:21:16 -0700358 GrGLenum matrixMode =
359 fGpu->glStandard() == kGLES_GrGLStandard ? GR_GL_PATH_PROJECTION : GR_GL_PROJECTION;
360 GL_CALL(MatrixLoadf(matrixMode, glMatrix));
kkinnunenccdaa042014-08-20 01:36:23 -0700361}
362
cdaltonc7103a12014-08-11 14:05:05 -0700363GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
364 if (range > 1) {
365 GrGLuint name;
366 GL_CALL_RET(name, GenPaths(range));
367 return name;
368 }
369
370 if (NULL == fPathNameAllocator.get()) {
371 static const int range = 65536;
372 GrGLuint firstName;
373 GL_CALL_RET(firstName, GenPaths(range));
374 fPathNameAllocator.reset(SkNEW_ARGS(GrGLNameAllocator, (firstName, firstName + range)));
375 }
376
377 // When allocating names one at a time, pull from a client-side pool of
378 // available names in order to save a round trip to the GL server.
379 GrGLuint name = fPathNameAllocator->allocateName();
380
381 if (0 == name) {
382 // Our reserved path names are all in use. Fall back on GenPaths.
383 GL_CALL_RET(name, GenPaths(1));
384 }
385
386 return name;
387}
388
kkinnunen5b653572014-08-20 04:13:27 -0700389void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
cdaltonc7103a12014-08-11 14:05:05 -0700390 if (range > 1) {
391 // It is not supported to delete names in ranges that were allocated
392 // individually using GrGLPathNameAllocator.
393 SkASSERT(NULL == fPathNameAllocator.get() ||
394 path + range <= fPathNameAllocator->firstName() ||
395 path >= fPathNameAllocator->endName());
396 GL_CALL(DeletePaths(path, range));
397 return;
398 }
399
400 if (NULL == fPathNameAllocator.get() ||
401 path < fPathNameAllocator->firstName() ||
402 path >= fPathNameAllocator->endName()) {
403 // If we aren't inside fPathNameAllocator's range then this name was
404 // generated by the GenPaths fallback (or else was never allocated).
405 GL_CALL(DeletePaths(path, 1));
406 return;
407 }
408
409 // Make the path empty to save memory, but don't free the name in the driver.
410 GL_CALL(PathCommands(path, 0, NULL, 0, GR_GL_FLOAT, NULL));
411 fPathNameAllocator->free(path);
412}
413
kkinnunen5b653572014-08-20 04:13:27 -0700414void GrGLPathRendering::flushPathStencilSettings(SkPath::FillType fill) {
415 GrStencilSettings pathStencilSettings;
416 fGpu->getPathStencilSettingsForFillType(fill, &pathStencilSettings);
417 if (fHWPathStencilSettings != pathStencilSettings) {
418 // Just the func, ref, and mask is set here. The op and write mask are params to the call
419 // that draws the path to the SB (glStencilFillPath)
420 GrGLenum func =
421 GrToGLStencilFunc(pathStencilSettings.func(GrStencilSettings::kFront_Face));
422 GL_CALL(PathStencilFunc(func, pathStencilSettings.funcRef(GrStencilSettings::kFront_Face),
423 pathStencilSettings.funcMask(GrStencilSettings::kFront_Face)));
424
425 fHWPathStencilSettings = pathStencilSettings;
426 }
cdaltonc7103a12014-08-11 14:05:05 -0700427}
428
kkinnunen5b653572014-08-20 04:13:27 -0700429inline void GrGLPathRendering::stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
cdaltonc7103a12014-08-11 14:05:05 -0700430 GrGLuint mask, GrGLenum coverMode) {
kkinnunen5b653572014-08-20 04:13:27 -0700431 if (caps().stencilThenCoverSupport) {
432 GL_CALL(StencilThenCoverFillPath(path, fillMode, mask, coverMode));
433 return;
434 }
cdaltonc7103a12014-08-11 14:05:05 -0700435 GL_CALL(StencilFillPath(path, fillMode, mask));
436 GL_CALL(CoverFillPath(path, coverMode));
437}
438
kkinnunen5b653572014-08-20 04:13:27 -0700439inline void GrGLPathRendering::stencilThenCoverStrokePath(GrGLuint path, GrGLint reference,
cdaltonc7103a12014-08-11 14:05:05 -0700440 GrGLuint mask, GrGLenum coverMode) {
kkinnunen5b653572014-08-20 04:13:27 -0700441 if (caps().stencilThenCoverSupport) {
442 GL_CALL(StencilThenCoverStrokePath(path, reference, mask, coverMode));
443 return;
444 }
cdaltonc7103a12014-08-11 14:05:05 -0700445 GL_CALL(StencilStrokePath(path, reference, mask));
446 GL_CALL(CoverStrokePath(path, coverMode));
447}
448
kkinnunen5b653572014-08-20 04:13:27 -0700449inline void GrGLPathRendering::stencilThenCoverFillPathInstanced(
cdaltonc7103a12014-08-11 14:05:05 -0700450 GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
451 GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode,
452 GrGLenum transformType, const GrGLfloat *transformValues) {
kkinnunen5b653572014-08-20 04:13:27 -0700453 if (caps().stencilThenCoverSupport) {
454 GL_CALL(StencilThenCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, fillMode,
455 mask, coverMode, transformType, transformValues));
456 return;
457 }
cdaltonc7103a12014-08-11 14:05:05 -0700458 GL_CALL(StencilFillPathInstanced(numPaths, pathNameType, paths, pathBase,
459 fillMode, mask, transformType, transformValues));
460 GL_CALL(CoverFillPathInstanced(numPaths, pathNameType, paths, pathBase,
461 coverMode, transformType, transformValues));
462}
463
kkinnunen5b653572014-08-20 04:13:27 -0700464inline void GrGLPathRendering::stencilThenCoverStrokePathInstanced(
465 GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
466 GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode,
467 GrGLenum transformType, const GrGLfloat *transformValues) {
468 if (caps().stencilThenCoverSupport) {
469 GL_CALL(StencilThenCoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
470 reference, mask, coverMode, transformType,
471 transformValues));
472 return;
473 }
474
cdaltonc7103a12014-08-11 14:05:05 -0700475 GL_CALL(StencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
476 reference, mask, transformType, transformValues));
477 GL_CALL(CoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
478 coverMode, transformType, transformValues));
479}