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 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 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 70 GrGLPathRendering::~GrGLPathRendering() { 71 } 72 73 void GrGLPathRendering::abandonGpuResources() { 74 fPathNameAllocator.reset(NULL); 75 } 76 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 95 GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const SkStrokeRec& stroke) { 96 return SkNEW_ARGS(GrGLPath, (fGpu, inPath, stroke)); 97 } 98 99 GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator, 100 const SkStrokeRec& stroke) { 101 return SkNEW_ARGS(GrGLPathRange, (fGpu, pathGenerator, stroke)); 102 } 103 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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