blob: 26584bc80872f4dffd8f864aff73478f0b8bb784 [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
kkinnunen5b653572014-08-20 04:13:27 -0700155void GrGLPathRendering::stencilPath(const GrPath* path, SkPath::FillType fill) {
156 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
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();
bsalomon49f085d2014-09-05 13:34:00 -0700171 SkASSERT(fGpu->drawState()->getRenderTarget());
172 SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
kkinnunen5b653572014-08-20 04:13:27 -0700173
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());
bsalomon49f085d2014-09-05 13:34:00 -0700227 SkASSERT(fGpu->drawState()->getRenderTarget());
228 SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
kkinnunen5b653572014-08-20 04:13:27 -0700229
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
kkinnunenccdaa042014-08-20 01:36:23 -0700299void 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;
kkinnunen5b653572014-08-20 04:13:27 -0700315 GL_CALL(PathTexGen(GR_GL_TEXTURE0 + unitIdx, GR_GL_OBJECT_LINEAR, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700316
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
kkinnunen5b653572014-08-20 04:13:27 -0700369void 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);
kkinnunenccdaa042014-08-20 01:36:23 -0700375
kkinnunen5b653572014-08-20 04:13:27 -0700376 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
377 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
378 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
kkinnunenccdaa042014-08-20 01:36:23 -0700379
kkinnunen5b653572014-08-20 04:13:27 -0700380 if (components >= 2) {
381 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
382 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
383 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
kkinnunenccdaa042014-08-20 01:36:23 -0700384 }
kkinnunenccdaa042014-08-20 01:36:23 -0700385
kkinnunen5b653572014-08-20 04:13:27 -0700386 if (components >= 3) {
387 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
388 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
389 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
kkinnunenccdaa042014-08-20 01:36:23 -0700390 }
kkinnunenccdaa042014-08-20 01:36:23 -0700391
kkinnunen5b653572014-08-20 04:13:27 -0700392 GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700393}
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);
kkinnunenec56e452014-08-25 22:21:16 -0700413 GrGLenum matrixMode =
414 fGpu->glStandard() == kGLES_GrGLStandard ? GR_GL_PATH_PROJECTION : GR_GL_PROJECTION;
415 GL_CALL(MatrixLoadf(matrixMode, glMatrix));
kkinnunenccdaa042014-08-20 01:36:23 -0700416}
417
cdaltonc7103a12014-08-11 14:05:05 -0700418GrGLuint 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
kkinnunen5b653572014-08-20 04:13:27 -0700444void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
cdaltonc7103a12014-08-11 14:05:05 -0700445 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
kkinnunen5b653572014-08-20 04:13:27 -0700469void 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 }
cdaltonc7103a12014-08-11 14:05:05 -0700482}
483
kkinnunen5b653572014-08-20 04:13:27 -0700484inline void GrGLPathRendering::stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
cdaltonc7103a12014-08-11 14:05:05 -0700485 GrGLuint mask, GrGLenum coverMode) {
kkinnunen5b653572014-08-20 04:13:27 -0700486 if (caps().stencilThenCoverSupport) {
487 GL_CALL(StencilThenCoverFillPath(path, fillMode, mask, coverMode));
488 return;
489 }
cdaltonc7103a12014-08-11 14:05:05 -0700490 GL_CALL(StencilFillPath(path, fillMode, mask));
491 GL_CALL(CoverFillPath(path, coverMode));
492}
493
kkinnunen5b653572014-08-20 04:13:27 -0700494inline void GrGLPathRendering::stencilThenCoverStrokePath(GrGLuint path, GrGLint reference,
cdaltonc7103a12014-08-11 14:05:05 -0700495 GrGLuint mask, GrGLenum coverMode) {
kkinnunen5b653572014-08-20 04:13:27 -0700496 if (caps().stencilThenCoverSupport) {
497 GL_CALL(StencilThenCoverStrokePath(path, reference, mask, coverMode));
498 return;
499 }
cdaltonc7103a12014-08-11 14:05:05 -0700500 GL_CALL(StencilStrokePath(path, reference, mask));
501 GL_CALL(CoverStrokePath(path, coverMode));
502}
503
kkinnunen5b653572014-08-20 04:13:27 -0700504inline void GrGLPathRendering::stencilThenCoverFillPathInstanced(
cdaltonc7103a12014-08-11 14:05:05 -0700505 GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
506 GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode,
507 GrGLenum transformType, const GrGLfloat *transformValues) {
kkinnunen5b653572014-08-20 04:13:27 -0700508 if (caps().stencilThenCoverSupport) {
509 GL_CALL(StencilThenCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, fillMode,
510 mask, coverMode, transformType, transformValues));
511 return;
512 }
cdaltonc7103a12014-08-11 14:05:05 -0700513 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
kkinnunen5b653572014-08-20 04:13:27 -0700519inline 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
cdaltonc7103a12014-08-11 14:05:05 -0700530 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}