blob: 2fe9758c8a469a8a5e03fc0f509a9cbe60989de1 [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);
135
136 GrGLenum status;
137 GL_CALL_RET(status, PathMemoryGlyphIndexArray(basePathID, GR_GL_STANDARD_FONT_FORMAT,
138 fontDataLength, fontData, faceIndex, 0, numPaths,
139 GrGLPath(fGpu, SkPath(), stroke).pathID(),
140 SkPaint::kCanonicalTextSizeForPaths));
141
142 if (GR_GL_FONT_GLYPHS_AVAILABLE != status) {
143 this->deletePaths(basePathID, numPaths);
144 return GrPathRendering::createGlyphs(typeface, NULL, stroke);
145 }
146
147 // This is a crude approximation. We may want to consider giving this class
148 // a pseudo PathGenerator whose sole purpose is to track the approximate gpu
149 // memory size.
150 const size_t gpuMemorySize = fontDataLength / 4;
151 return SkNEW_ARGS(GrGLPathRange, (fGpu, basePathID, numPaths, gpuMemorySize, stroke));
kkinnunenccdaa042014-08-20 01:36:23 -0700152}
153
kkinnunen5b653572014-08-20 04:13:27 -0700154void GrGLPathRendering::stencilPath(const GrPath* path, SkPath::FillType fill) {
155 GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
bsalomon49f085d2014-09-05 13:34:00 -0700156 SkASSERT(fGpu->drawState()->getRenderTarget());
157 SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
kkinnunen5b653572014-08-20 04:13:27 -0700158
159 this->flushPathStencilSettings(fill);
160 SkASSERT(!fHWPathStencilSettings.isTwoSided());
161
162 GrGLenum fillMode =
163 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
164 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
165 GL_CALL(StencilFillPath(id, fillMode, writeMask));
166}
167
168void GrGLPathRendering::drawPath(const GrPath* path, SkPath::FillType fill) {
169 GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
bsalomon49f085d2014-09-05 13:34:00 -0700170 SkASSERT(fGpu->drawState()->getRenderTarget());
171 SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
kkinnunen5b653572014-08-20 04:13:27 -0700172
173 this->flushPathStencilSettings(fill);
174 SkASSERT(!fHWPathStencilSettings.isTwoSided());
175
176 const SkStrokeRec& stroke = path->getStroke();
177
178 SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(fill);
179
180 GrGLenum fillMode =
181 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
182 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
183
184 if (nonInvertedFill == fill) {
185 if (stroke.needToApply()) {
186 if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
187 GL_CALL(StencilFillPath(id, fillMode, writeMask));
188 }
189 this->stencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX);
190 } else {
191 this->stencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX);
192 }
193 } else {
194 if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
195 GL_CALL(StencilFillPath(id, fillMode, writeMask));
196 }
197 if (stroke.needToApply()) {
198 GL_CALL(StencilStrokePath(id, 0xffff, writeMask));
199 }
200
201 GrDrawState* drawState = fGpu->drawState();
202 GrDrawState::AutoViewMatrixRestore avmr;
203 SkRect bounds = SkRect::MakeLTRB(0, 0,
204 SkIntToScalar(drawState->getRenderTarget()->width()),
205 SkIntToScalar(drawState->getRenderTarget()->height()));
206 SkMatrix vmi;
207 // mapRect through persp matrix may not be correct
208 if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
209 vmi.mapRect(&bounds);
210 // theoretically could set bloat = 0, instead leave it because of matrix inversion
211 // precision.
212 SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf;
213 bounds.outset(bloat, bloat);
214 } else {
215 avmr.setIdentity(drawState);
216 }
217
218 fGpu->drawSimpleRect(bounds);
219 }
220}
221
222void GrGLPathRendering::drawPaths(const GrPathRange* pathRange, const uint32_t indices[], int count,
223 const float transforms[], PathTransformType transformsType,
224 SkPath::FillType fill) {
225 SkASSERT(fGpu->caps()->pathRenderingSupport());
bsalomon49f085d2014-09-05 13:34:00 -0700226 SkASSERT(fGpu->drawState()->getRenderTarget());
227 SkASSERT(fGpu->drawState()->getRenderTarget()->getStencilBuffer());
kkinnunen5b653572014-08-20 04:13:27 -0700228
229 GrGLuint baseID = static_cast<const GrGLPathRange*>(pathRange)->basePathID();
230
231 this->flushPathStencilSettings(fill);
232 SkASSERT(!fHWPathStencilSettings.isTwoSided());
233
234 const SkStrokeRec& stroke = pathRange->getStroke();
235
236 SkPath::FillType nonInvertedFill =
237 SkPath::ConvertToNonInverseFillType(fill);
238
239 GrGLenum fillMode =
240 gr_stencil_op_to_gl_path_rendering_fill_mode(
241 fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
242 GrGLint writeMask =
243 fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
244
245 if (nonInvertedFill == fill) {
246 if (stroke.needToApply()) {
247 if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
248 GL_CALL(StencilFillPathInstanced(
249 count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
250 writeMask, gXformType2GLType[transformsType],
251 transforms));
252 }
253 this->stencilThenCoverStrokePathInstanced(
254 count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff, writeMask,
255 GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
256 gXformType2GLType[transformsType], transforms);
257 } else {
258 this->stencilThenCoverFillPathInstanced(
259 count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode, writeMask,
260 GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
261 gXformType2GLType[transformsType], transforms);
262 }
263 } else {
264 if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
265 GL_CALL(StencilFillPathInstanced(
266 count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
267 writeMask, gXformType2GLType[transformsType],
268 transforms));
269 }
270 if (stroke.needToApply()) {
271 GL_CALL(StencilStrokePathInstanced(
272 count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff,
273 writeMask, gXformType2GLType[transformsType],
274 transforms));
275 }
276
277 GrDrawState* drawState = fGpu->drawState();
278 GrDrawState::AutoViewMatrixRestore avmr;
279 SkRect bounds = SkRect::MakeLTRB(0, 0,
280 SkIntToScalar(drawState->getRenderTarget()->width()),
281 SkIntToScalar(drawState->getRenderTarget()->height()));
282 SkMatrix vmi;
283 // mapRect through persp matrix may not be correct
284 if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
285 vmi.mapRect(&bounds);
286 // theoretically could set bloat = 0, instead leave it because of matrix inversion
287 // precision.
288 SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf;
289 bounds.outset(bloat, bloat);
290 } else {
291 avmr.setIdentity(drawState);
292 }
293
294 fGpu->drawSimpleRect(bounds);
295 }
296}
297
kkinnunenccdaa042014-08-20 01:36:23 -0700298void GrGLPathRendering::enablePathTexGen(int unitIdx, PathTexGenComponents components,
299 const GrGLfloat* coefficients) {
300 SkASSERT(components >= kS_PathTexGenComponents &&
301 components <= kSTR_PathTexGenComponents);
302 SkASSERT(fGpu->glCaps().maxFixedFunctionTextureCoords() >= unitIdx);
303
304 if (GR_GL_OBJECT_LINEAR == fHWPathTexGenSettings[unitIdx].fMode &&
305 components == fHWPathTexGenSettings[unitIdx].fNumComponents &&
306 !memcmp(coefficients, fHWPathTexGenSettings[unitIdx].fCoefficients,
307 3 * components * sizeof(GrGLfloat))) {
308 return;
309 }
310
311 fGpu->setTextureUnit(unitIdx);
312
313 fHWPathTexGenSettings[unitIdx].fNumComponents = components;
kkinnunen5b653572014-08-20 04:13:27 -0700314 GL_CALL(PathTexGen(GR_GL_TEXTURE0 + unitIdx, GR_GL_OBJECT_LINEAR, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700315
316 memcpy(fHWPathTexGenSettings[unitIdx].fCoefficients, coefficients,
317 3 * components * sizeof(GrGLfloat));
318}
319
320void GrGLPathRendering::enablePathTexGen(int unitIdx, PathTexGenComponents components,
321 const SkMatrix& matrix) {
322 GrGLfloat coefficients[3 * 3];
323 SkASSERT(components >= kS_PathTexGenComponents &&
324 components <= kSTR_PathTexGenComponents);
325
326 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
327 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
328 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
329
330 if (components >= kST_PathTexGenComponents) {
331 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
332 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
333 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
334 }
335
336 if (components >= kSTR_PathTexGenComponents) {
337 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
338 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
339 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
340 }
341
342 this->enablePathTexGen(unitIdx, components, coefficients);
343}
344
345void GrGLPathRendering::flushPathTexGenSettings(int numUsedTexCoordSets) {
346 SkASSERT(fGpu->glCaps().maxFixedFunctionTextureCoords() >= numUsedTexCoordSets);
347
348 // Only write the inactive path tex gens, since active path tex gens were
349 // written when they were enabled.
350
351 SkDEBUGCODE(
352 for (int i = 0; i < numUsedTexCoordSets; i++) {
353 SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
354 }
355 );
356
357 for (int i = numUsedTexCoordSets; i < fHWActivePathTexGenSets; i++) {
358 SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
359
360 fGpu->setTextureUnit(i);
361 GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
362 fHWPathTexGenSettings[i].fNumComponents = 0;
363 }
364
365 fHWActivePathTexGenSets = numUsedTexCoordSets;
366}
367
kkinnunen5b653572014-08-20 04:13:27 -0700368void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
369 GrGLenum genMode, GrGLint components,
370 const SkMatrix& matrix) {
371 SkASSERT(caps().fragmentInputGenSupport);
372 GrGLfloat coefficients[3 * 3];
373 SkASSERT(components >= 1 && components <= 3);
kkinnunenccdaa042014-08-20 01:36:23 -0700374
kkinnunen5b653572014-08-20 04:13:27 -0700375 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
376 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
377 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
kkinnunenccdaa042014-08-20 01:36:23 -0700378
kkinnunen5b653572014-08-20 04:13:27 -0700379 if (components >= 2) {
380 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
381 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
382 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
kkinnunenccdaa042014-08-20 01:36:23 -0700383 }
kkinnunenccdaa042014-08-20 01:36:23 -0700384
kkinnunen5b653572014-08-20 04:13:27 -0700385 if (components >= 3) {
386 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
387 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
388 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
kkinnunenccdaa042014-08-20 01:36:23 -0700389 }
kkinnunenccdaa042014-08-20 01:36:23 -0700390
kkinnunen5b653572014-08-20 04:13:27 -0700391 GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700392}
393
394void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
395 const SkISize& renderTargetSize,
396 GrSurfaceOrigin renderTargetOrigin) {
397
398 SkASSERT(fGpu->glCaps().pathRenderingSupport());
399
400 if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
401 renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
402 matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
403 return;
404 }
405
406 fHWProjectionMatrixState.fViewMatrix = matrix;
407 fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
408 fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
409
410 GrGLfloat glMatrix[4 * 4];
411 fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
kkinnunenec56e452014-08-25 22:21:16 -0700412 GrGLenum matrixMode =
413 fGpu->glStandard() == kGLES_GrGLStandard ? GR_GL_PATH_PROJECTION : GR_GL_PROJECTION;
414 GL_CALL(MatrixLoadf(matrixMode, glMatrix));
kkinnunenccdaa042014-08-20 01:36:23 -0700415}
416
cdaltonc7103a12014-08-11 14:05:05 -0700417GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
418 if (range > 1) {
419 GrGLuint name;
420 GL_CALL_RET(name, GenPaths(range));
421 return name;
422 }
423
424 if (NULL == fPathNameAllocator.get()) {
425 static const int range = 65536;
426 GrGLuint firstName;
427 GL_CALL_RET(firstName, GenPaths(range));
428 fPathNameAllocator.reset(SkNEW_ARGS(GrGLNameAllocator, (firstName, firstName + range)));
429 }
430
431 // When allocating names one at a time, pull from a client-side pool of
432 // available names in order to save a round trip to the GL server.
433 GrGLuint name = fPathNameAllocator->allocateName();
434
435 if (0 == name) {
436 // Our reserved path names are all in use. Fall back on GenPaths.
437 GL_CALL_RET(name, GenPaths(1));
438 }
439
440 return name;
441}
442
kkinnunen5b653572014-08-20 04:13:27 -0700443void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
cdaltonc7103a12014-08-11 14:05:05 -0700444 if (range > 1) {
445 // It is not supported to delete names in ranges that were allocated
446 // individually using GrGLPathNameAllocator.
447 SkASSERT(NULL == fPathNameAllocator.get() ||
448 path + range <= fPathNameAllocator->firstName() ||
449 path >= fPathNameAllocator->endName());
450 GL_CALL(DeletePaths(path, range));
451 return;
452 }
453
454 if (NULL == fPathNameAllocator.get() ||
455 path < fPathNameAllocator->firstName() ||
456 path >= fPathNameAllocator->endName()) {
457 // If we aren't inside fPathNameAllocator's range then this name was
458 // generated by the GenPaths fallback (or else was never allocated).
459 GL_CALL(DeletePaths(path, 1));
460 return;
461 }
462
463 // Make the path empty to save memory, but don't free the name in the driver.
464 GL_CALL(PathCommands(path, 0, NULL, 0, GR_GL_FLOAT, NULL));
465 fPathNameAllocator->free(path);
466}
467
kkinnunen5b653572014-08-20 04:13:27 -0700468void GrGLPathRendering::flushPathStencilSettings(SkPath::FillType fill) {
469 GrStencilSettings pathStencilSettings;
470 fGpu->getPathStencilSettingsForFillType(fill, &pathStencilSettings);
471 if (fHWPathStencilSettings != pathStencilSettings) {
472 // Just the func, ref, and mask is set here. The op and write mask are params to the call
473 // that draws the path to the SB (glStencilFillPath)
474 GrGLenum func =
475 GrToGLStencilFunc(pathStencilSettings.func(GrStencilSettings::kFront_Face));
476 GL_CALL(PathStencilFunc(func, pathStencilSettings.funcRef(GrStencilSettings::kFront_Face),
477 pathStencilSettings.funcMask(GrStencilSettings::kFront_Face)));
478
479 fHWPathStencilSettings = pathStencilSettings;
480 }
cdaltonc7103a12014-08-11 14:05:05 -0700481}
482
kkinnunen5b653572014-08-20 04:13:27 -0700483inline void GrGLPathRendering::stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
cdaltonc7103a12014-08-11 14:05:05 -0700484 GrGLuint mask, GrGLenum coverMode) {
kkinnunen5b653572014-08-20 04:13:27 -0700485 if (caps().stencilThenCoverSupport) {
486 GL_CALL(StencilThenCoverFillPath(path, fillMode, mask, coverMode));
487 return;
488 }
cdaltonc7103a12014-08-11 14:05:05 -0700489 GL_CALL(StencilFillPath(path, fillMode, mask));
490 GL_CALL(CoverFillPath(path, coverMode));
491}
492
kkinnunen5b653572014-08-20 04:13:27 -0700493inline void GrGLPathRendering::stencilThenCoverStrokePath(GrGLuint path, GrGLint reference,
cdaltonc7103a12014-08-11 14:05:05 -0700494 GrGLuint mask, GrGLenum coverMode) {
kkinnunen5b653572014-08-20 04:13:27 -0700495 if (caps().stencilThenCoverSupport) {
496 GL_CALL(StencilThenCoverStrokePath(path, reference, mask, coverMode));
497 return;
498 }
cdaltonc7103a12014-08-11 14:05:05 -0700499 GL_CALL(StencilStrokePath(path, reference, mask));
500 GL_CALL(CoverStrokePath(path, coverMode));
501}
502
kkinnunen5b653572014-08-20 04:13:27 -0700503inline void GrGLPathRendering::stencilThenCoverFillPathInstanced(
cdaltonc7103a12014-08-11 14:05:05 -0700504 GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
505 GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode,
506 GrGLenum transformType, const GrGLfloat *transformValues) {
kkinnunen5b653572014-08-20 04:13:27 -0700507 if (caps().stencilThenCoverSupport) {
508 GL_CALL(StencilThenCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, fillMode,
509 mask, coverMode, transformType, transformValues));
510 return;
511 }
cdaltonc7103a12014-08-11 14:05:05 -0700512 GL_CALL(StencilFillPathInstanced(numPaths, pathNameType, paths, pathBase,
513 fillMode, mask, transformType, transformValues));
514 GL_CALL(CoverFillPathInstanced(numPaths, pathNameType, paths, pathBase,
515 coverMode, transformType, transformValues));
516}
517
kkinnunen5b653572014-08-20 04:13:27 -0700518inline void GrGLPathRendering::stencilThenCoverStrokePathInstanced(
519 GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
520 GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode,
521 GrGLenum transformType, const GrGLfloat *transformValues) {
522 if (caps().stencilThenCoverSupport) {
523 GL_CALL(StencilThenCoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
524 reference, mask, coverMode, transformType,
525 transformValues));
526 return;
527 }
528
cdaltonc7103a12014-08-11 14:05:05 -0700529 GL_CALL(StencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
530 reference, mask, transformType, transformValues));
531 GL_CALL(CoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
532 coverMode, transformType, transformValues));
533}