blob: 66b129e8768e3fb065e1d1c6582bff0fe06730b4 [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
cdalton855d83f2014-09-18 13:51:53 -070017#include "SkStream.h"
18#include "SkTypeface.h"
19
kkinnunenccdaa042014-08-20 01:36:23 -070020#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}
cdaltonc7103a12014-08-11 14:05:05 -070050
kkinnunenccdaa042014-08-20 01:36:23 -070051GrGLPathRendering::GrGLPathRendering(GrGpuGL* gpu)
52 : fGpu(gpu) {
kkinnunen5b653572014-08-20 04:13:27 -070053 const GrGLInterface* glInterface = gpu->glInterface();
54 fCaps.stencilThenCoverSupport =
cdalton149b3ec2014-09-17 09:19:18 -070055 NULL != glInterface->fFunctions.fStencilThenCoverFillPath &&
56 NULL != glInterface->fFunctions.fStencilThenCoverStrokePath &&
57 NULL != glInterface->fFunctions.fStencilThenCoverFillPathInstanced &&
58 NULL != glInterface->fFunctions.fStencilThenCoverStrokePathInstanced;
kkinnunen5b653572014-08-20 04:13:27 -070059 fCaps.fragmentInputGenSupport =
kkinnunenec56e452014-08-25 22:21:16 -070060 kGLES_GrGLStandard == glInterface->fStandard &&
cdalton149b3ec2014-09-17 09:19:18 -070061 NULL != glInterface->fFunctions.fProgramPathFragmentInputGen;
62 fCaps.glyphLoadingSupport =
63 NULL != glInterface->fFunctions.fPathMemoryGlyphIndexArray;
kkinnunenec56e452014-08-25 22:21:16 -070064
65 if (!fCaps.fragmentInputGenSupport) {
66 fHWPathTexGenSettings.reset(fGpu->glCaps().maxFixedFunctionTextureCoords());
67 }
cdaltonc7103a12014-08-11 14:05:05 -070068}
69
70GrGLPathRendering::~GrGLPathRendering() {
71}
72
73void GrGLPathRendering::abandonGpuResources() {
74 fPathNameAllocator.reset(NULL);
75}
76
kkinnunenccdaa042014-08-20 01:36:23 -070077void GrGLPathRendering::resetContext() {
78 fHWProjectionMatrixState.invalidate();
79 // we don't use the model view matrix.
kkinnunenec56e452014-08-25 22:21:16 -070080 GrGLenum matrixMode =
81 fGpu->glStandard() == kGLES_GrGLStandard ? GR_GL_PATH_MODELVIEW : GR_GL_MODELVIEW;
82 GL_CALL(MatrixLoadIdentity(matrixMode));
kkinnunenccdaa042014-08-20 01:36:23 -070083
kkinnunenec56e452014-08-25 22:21:16 -070084 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;
kkinnunenccdaa042014-08-20 01:36:23 -070091 }
kkinnunenccdaa042014-08-20 01:36:23 -070092 fHWPathStencilSettings.invalidate();
93}
94
95GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const SkStrokeRec& stroke) {
96 return SkNEW_ARGS(GrGLPath, (fGpu, inPath, stroke));
97}
98
cdalton855d83f2014-09-18 13:51:53 -070099GrPathRange* 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);
cdalton544c5b82014-09-19 11:12:46 -0700135 SkAutoTUnref<GrGLPath> templatePath(SkNEW_ARGS(GrGLPath, (fGpu, SkPath(), stroke)));
cdalton855d83f2014-09-18 13:51:53 -0700136
137 GrGLenum status;
138 GL_CALL_RET(status, PathMemoryGlyphIndexArray(basePathID, GR_GL_STANDARD_FONT_FORMAT,
cdalton544c5b82014-09-19 11:12:46 -0700139 fontDataLength, fontData, faceIndex, 0,
140 numPaths, templatePath->pathID(),
cdalton855d83f2014-09-18 13:51:53 -0700141 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));
kkinnunenccdaa042014-08-20 01:36:23 -0700153}
154
joshualitt92e496f2014-10-31 13:56:50 -0700155void GrGLPathRendering::stencilPath(const GrPath* path, const GrStencilSettings& stencilSettings) {
kkinnunen5b653572014-08-20 04:13:27 -0700156 GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
bsalomon49f085d2014-09-05 13:34:00 -0700157 SkASSERT(fGpu->drawState()->getRenderTarget());
158 SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
kkinnunen5b653572014-08-20 04:13:27 -0700159
joshualitt92e496f2014-10-31 13:56:50 -0700160 this->flushPathStencilSettings(stencilSettings);
kkinnunen5b653572014-08-20 04:13:27 -0700161 SkASSERT(!fHWPathStencilSettings.isTwoSided());
162
163 const SkStrokeRec& stroke = path->getStroke();
164
joshualitt92e496f2014-10-31 13:56:50 -0700165 GrGLenum fillMode =
166 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
167 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
168
169 if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
170 GL_CALL(StencilFillPath(id, fillMode, writeMask));
171 }
172 if (stroke.needToApply()) {
173 GL_CALL(StencilStrokePath(id, 0xffff, writeMask));
174 }
175}
176
177void GrGLPathRendering::drawPath(const GrPath* path, const GrStencilSettings& stencilSettings) {
178 GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
179 SkASSERT(fGpu->drawState()->getRenderTarget());
180 SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
181
182 this->flushPathStencilSettings(stencilSettings);
183 SkASSERT(!fHWPathStencilSettings.isTwoSided());
184
185 const SkStrokeRec& stroke = path->getStroke();
kkinnunen5b653572014-08-20 04:13:27 -0700186
187 GrGLenum fillMode =
188 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
189 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
190
joshualitt92e496f2014-10-31 13:56:50 -0700191 if (stroke.needToApply()) {
192 if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
kkinnunen5b653572014-08-20 04:13:27 -0700193 GL_CALL(StencilFillPath(id, fillMode, writeMask));
194 }
joshualitt92e496f2014-10-31 13:56:50 -0700195 this->stencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX);
196 } else {
197 this->stencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX);
kkinnunen5b653572014-08-20 04:13:27 -0700198 }
199}
200
201void GrGLPathRendering::drawPaths(const GrPathRange* pathRange, const uint32_t indices[], int count,
202 const float transforms[], PathTransformType transformsType,
joshualitt92e496f2014-10-31 13:56:50 -0700203 const GrStencilSettings& stencilSettings) {
kkinnunen5b653572014-08-20 04:13:27 -0700204 SkASSERT(fGpu->caps()->pathRenderingSupport());
bsalomon49f085d2014-09-05 13:34:00 -0700205 SkASSERT(fGpu->drawState()->getRenderTarget());
206 SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
kkinnunen5b653572014-08-20 04:13:27 -0700207
208 GrGLuint baseID = static_cast<const GrGLPathRange*>(pathRange)->basePathID();
209
joshualitt92e496f2014-10-31 13:56:50 -0700210 this->flushPathStencilSettings(stencilSettings);
kkinnunen5b653572014-08-20 04:13:27 -0700211 SkASSERT(!fHWPathStencilSettings.isTwoSided());
212
213 const SkStrokeRec& stroke = pathRange->getStroke();
214
kkinnunen5b653572014-08-20 04:13:27 -0700215 GrGLenum fillMode =
216 gr_stencil_op_to_gl_path_rendering_fill_mode(
217 fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
218 GrGLint writeMask =
219 fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
220
joshualitt92e496f2014-10-31 13:56:50 -0700221 if (stroke.needToApply()) {
222 if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
kkinnunen5b653572014-08-20 04:13:27 -0700223 GL_CALL(StencilFillPathInstanced(
joshualitt92e496f2014-10-31 13:56:50 -0700224 count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
225 writeMask, gXformType2GLType[transformsType],
226 transforms));
kkinnunen5b653572014-08-20 04:13:27 -0700227 }
joshualitt92e496f2014-10-31 13:56:50 -0700228 this->stencilThenCoverStrokePathInstanced(
229 count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff, writeMask,
230 GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
231 gXformType2GLType[transformsType], transforms);
232 } else {
233 this->stencilThenCoverFillPathInstanced(
234 count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode, writeMask,
235 GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
236 gXformType2GLType[transformsType], transforms);
kkinnunen5b653572014-08-20 04:13:27 -0700237 }
238}
239
kkinnunenccdaa042014-08-20 01:36:23 -0700240void GrGLPathRendering::enablePathTexGen(int unitIdx, PathTexGenComponents components,
241 const GrGLfloat* coefficients) {
242 SkASSERT(components >= kS_PathTexGenComponents &&
243 components <= kSTR_PathTexGenComponents);
244 SkASSERT(fGpu->glCaps().maxFixedFunctionTextureCoords() >= unitIdx);
245
246 if (GR_GL_OBJECT_LINEAR == fHWPathTexGenSettings[unitIdx].fMode &&
247 components == fHWPathTexGenSettings[unitIdx].fNumComponents &&
248 !memcmp(coefficients, fHWPathTexGenSettings[unitIdx].fCoefficients,
249 3 * components * sizeof(GrGLfloat))) {
250 return;
251 }
252
253 fGpu->setTextureUnit(unitIdx);
254
255 fHWPathTexGenSettings[unitIdx].fNumComponents = components;
kkinnunen5b653572014-08-20 04:13:27 -0700256 GL_CALL(PathTexGen(GR_GL_TEXTURE0 + unitIdx, GR_GL_OBJECT_LINEAR, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700257
258 memcpy(fHWPathTexGenSettings[unitIdx].fCoefficients, coefficients,
259 3 * components * sizeof(GrGLfloat));
260}
261
262void GrGLPathRendering::enablePathTexGen(int unitIdx, PathTexGenComponents components,
263 const SkMatrix& matrix) {
264 GrGLfloat coefficients[3 * 3];
265 SkASSERT(components >= kS_PathTexGenComponents &&
266 components <= kSTR_PathTexGenComponents);
267
268 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
269 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
270 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
271
272 if (components >= kST_PathTexGenComponents) {
273 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
274 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
275 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
276 }
277
278 if (components >= kSTR_PathTexGenComponents) {
279 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
280 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
281 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
282 }
283
284 this->enablePathTexGen(unitIdx, components, coefficients);
285}
286
287void GrGLPathRendering::flushPathTexGenSettings(int numUsedTexCoordSets) {
288 SkASSERT(fGpu->glCaps().maxFixedFunctionTextureCoords() >= numUsedTexCoordSets);
289
290 // Only write the inactive path tex gens, since active path tex gens were
291 // written when they were enabled.
292
293 SkDEBUGCODE(
294 for (int i = 0; i < numUsedTexCoordSets; i++) {
295 SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
296 }
297 );
298
299 for (int i = numUsedTexCoordSets; i < fHWActivePathTexGenSets; i++) {
300 SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
301
302 fGpu->setTextureUnit(i);
303 GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
304 fHWPathTexGenSettings[i].fNumComponents = 0;
305 }
306
307 fHWActivePathTexGenSets = numUsedTexCoordSets;
308}
309
kkinnunen5b653572014-08-20 04:13:27 -0700310void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
311 GrGLenum genMode, GrGLint components,
312 const SkMatrix& matrix) {
313 SkASSERT(caps().fragmentInputGenSupport);
314 GrGLfloat coefficients[3 * 3];
315 SkASSERT(components >= 1 && components <= 3);
kkinnunenccdaa042014-08-20 01:36:23 -0700316
kkinnunen5b653572014-08-20 04:13:27 -0700317 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
318 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
319 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
kkinnunenccdaa042014-08-20 01:36:23 -0700320
kkinnunen5b653572014-08-20 04:13:27 -0700321 if (components >= 2) {
322 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
323 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
324 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
kkinnunenccdaa042014-08-20 01:36:23 -0700325 }
kkinnunenccdaa042014-08-20 01:36:23 -0700326
kkinnunen5b653572014-08-20 04:13:27 -0700327 if (components >= 3) {
328 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
329 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
330 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
kkinnunenccdaa042014-08-20 01:36:23 -0700331 }
kkinnunenccdaa042014-08-20 01:36:23 -0700332
kkinnunen5b653572014-08-20 04:13:27 -0700333 GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700334}
335
336void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
337 const SkISize& renderTargetSize,
338 GrSurfaceOrigin renderTargetOrigin) {
339
340 SkASSERT(fGpu->glCaps().pathRenderingSupport());
341
342 if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
343 renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
344 matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
345 return;
346 }
347
348 fHWProjectionMatrixState.fViewMatrix = matrix;
349 fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
350 fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
351
352 GrGLfloat glMatrix[4 * 4];
353 fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
kkinnunenec56e452014-08-25 22:21:16 -0700354 GrGLenum matrixMode =
355 fGpu->glStandard() == kGLES_GrGLStandard ? GR_GL_PATH_PROJECTION : GR_GL_PROJECTION;
356 GL_CALL(MatrixLoadf(matrixMode, glMatrix));
kkinnunenccdaa042014-08-20 01:36:23 -0700357}
358
cdaltonc7103a12014-08-11 14:05:05 -0700359GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
360 if (range > 1) {
361 GrGLuint name;
362 GL_CALL_RET(name, GenPaths(range));
363 return name;
364 }
365
366 if (NULL == fPathNameAllocator.get()) {
367 static const int range = 65536;
368 GrGLuint firstName;
369 GL_CALL_RET(firstName, GenPaths(range));
370 fPathNameAllocator.reset(SkNEW_ARGS(GrGLNameAllocator, (firstName, firstName + range)));
371 }
372
373 // When allocating names one at a time, pull from a client-side pool of
374 // available names in order to save a round trip to the GL server.
375 GrGLuint name = fPathNameAllocator->allocateName();
376
377 if (0 == name) {
378 // Our reserved path names are all in use. Fall back on GenPaths.
379 GL_CALL_RET(name, GenPaths(1));
380 }
381
382 return name;
383}
384
kkinnunen5b653572014-08-20 04:13:27 -0700385void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
cdaltonc7103a12014-08-11 14:05:05 -0700386 if (range > 1) {
387 // It is not supported to delete names in ranges that were allocated
388 // individually using GrGLPathNameAllocator.
389 SkASSERT(NULL == fPathNameAllocator.get() ||
390 path + range <= fPathNameAllocator->firstName() ||
391 path >= fPathNameAllocator->endName());
392 GL_CALL(DeletePaths(path, range));
393 return;
394 }
395
396 if (NULL == fPathNameAllocator.get() ||
397 path < fPathNameAllocator->firstName() ||
398 path >= fPathNameAllocator->endName()) {
399 // If we aren't inside fPathNameAllocator's range then this name was
400 // generated by the GenPaths fallback (or else was never allocated).
401 GL_CALL(DeletePaths(path, 1));
402 return;
403 }
404
405 // Make the path empty to save memory, but don't free the name in the driver.
406 GL_CALL(PathCommands(path, 0, NULL, 0, GR_GL_FLOAT, NULL));
407 fPathNameAllocator->free(path);
408}
409
joshualitt92e496f2014-10-31 13:56:50 -0700410void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
411 if (fHWPathStencilSettings != stencilSettings) {
kkinnunen5b653572014-08-20 04:13:27 -0700412 // Just the func, ref, and mask is set here. The op and write mask are params to the call
413 // that draws the path to the SB (glStencilFillPath)
414 GrGLenum func =
joshualitt92e496f2014-10-31 13:56:50 -0700415 GrToGLStencilFunc(stencilSettings.func(GrStencilSettings::kFront_Face));
416 GL_CALL(PathStencilFunc(func, stencilSettings.funcRef(GrStencilSettings::kFront_Face),
417 stencilSettings.funcMask(GrStencilSettings::kFront_Face)));
kkinnunen5b653572014-08-20 04:13:27 -0700418
joshualitt92e496f2014-10-31 13:56:50 -0700419 fHWPathStencilSettings = stencilSettings;
kkinnunen5b653572014-08-20 04:13:27 -0700420 }
cdaltonc7103a12014-08-11 14:05:05 -0700421}
422
kkinnunen5b653572014-08-20 04:13:27 -0700423inline void GrGLPathRendering::stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
cdaltonc7103a12014-08-11 14:05:05 -0700424 GrGLuint mask, GrGLenum coverMode) {
kkinnunen5b653572014-08-20 04:13:27 -0700425 if (caps().stencilThenCoverSupport) {
426 GL_CALL(StencilThenCoverFillPath(path, fillMode, mask, coverMode));
427 return;
428 }
cdaltonc7103a12014-08-11 14:05:05 -0700429 GL_CALL(StencilFillPath(path, fillMode, mask));
430 GL_CALL(CoverFillPath(path, coverMode));
431}
432
kkinnunen5b653572014-08-20 04:13:27 -0700433inline void GrGLPathRendering::stencilThenCoverStrokePath(GrGLuint path, GrGLint reference,
cdaltonc7103a12014-08-11 14:05:05 -0700434 GrGLuint mask, GrGLenum coverMode) {
kkinnunen5b653572014-08-20 04:13:27 -0700435 if (caps().stencilThenCoverSupport) {
436 GL_CALL(StencilThenCoverStrokePath(path, reference, mask, coverMode));
437 return;
438 }
cdaltonc7103a12014-08-11 14:05:05 -0700439 GL_CALL(StencilStrokePath(path, reference, mask));
440 GL_CALL(CoverStrokePath(path, coverMode));
441}
442
kkinnunen5b653572014-08-20 04:13:27 -0700443inline void GrGLPathRendering::stencilThenCoverFillPathInstanced(
cdaltonc7103a12014-08-11 14:05:05 -0700444 GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
445 GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode,
446 GrGLenum transformType, const GrGLfloat *transformValues) {
kkinnunen5b653572014-08-20 04:13:27 -0700447 if (caps().stencilThenCoverSupport) {
448 GL_CALL(StencilThenCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, fillMode,
449 mask, coverMode, transformType, transformValues));
450 return;
451 }
cdaltonc7103a12014-08-11 14:05:05 -0700452 GL_CALL(StencilFillPathInstanced(numPaths, pathNameType, paths, pathBase,
453 fillMode, mask, transformType, transformValues));
454 GL_CALL(CoverFillPathInstanced(numPaths, pathNameType, paths, pathBase,
455 coverMode, transformType, transformValues));
456}
457
kkinnunen5b653572014-08-20 04:13:27 -0700458inline void GrGLPathRendering::stencilThenCoverStrokePathInstanced(
459 GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
460 GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode,
461 GrGLenum transformType, const GrGLfloat *transformValues) {
462 if (caps().stencilThenCoverSupport) {
463 GL_CALL(StencilThenCoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
464 reference, mask, coverMode, transformType,
465 transformValues));
466 return;
467 }
468
cdaltonc7103a12014-08-11 14:05:05 -0700469 GL_CALL(StencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
470 reference, mask, transformType, transformValues));
471 GL_CALL(CoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
472 coverMode, transformType, transformValues));
473}