blob: 53d7cf007411ab4fbc7dcd3bf55f5ac2b5915d5c [file] [log] [blame]
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gl/GrGLPathRendering.h"
#include "gl/GrGLNameAllocator.h"
#include "gl/GrGLUtil.h"
#include "gl/GrGpuGL.h"
#include "GrGLPath.h"
#include "GrGLPathRange.h"
#include "GrGLPathRendering.h"
#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(fGpu->glInterface(), RET, X)
static const GrGLenum gXformType2GLType[] = {
GR_GL_NONE,
GR_GL_TRANSLATE_X,
GR_GL_TRANSLATE_Y,
GR_GL_TRANSLATE_2D,
GR_GL_TRANSPOSE_AFFINE_2D
};
GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
switch (op) {
default:
SkFAIL("Unexpected path fill.");
/* fallthrough */;
case kIncClamp_StencilOp:
return GR_GL_COUNT_UP;
case kInvert_StencilOp:
return GR_GL_INVERT;
}
}
class GrGLPathRenderingV12 : public GrGLPathRendering {
public:
GrGLPathRenderingV12(GrGpuGL* gpu)
: GrGLPathRendering(gpu) {
}
virtual GrGLvoid stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
GrGLuint mask, GrGLenum coverMode) SK_OVERRIDE;
virtual GrGLvoid stencilThenCoverStrokePath(GrGLuint path, GrGLint reference,
GrGLuint mask, GrGLenum coverMode) SK_OVERRIDE;
virtual GrGLvoid stencilThenCoverFillPathInstanced(
GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode,
GrGLenum transformType, const GrGLfloat *transformValues) SK_OVERRIDE;
virtual GrGLvoid stencilThenCoverStrokePathInstanced(
GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode,
GrGLenum transformType, const GrGLfloat *transformValues) SK_OVERRIDE;
};
class GrGLPathRenderingV13 : public GrGLPathRenderingV12 {
public:
GrGLPathRenderingV13(GrGpuGL* gpu)
: GrGLPathRenderingV12(gpu) {
fCaps.fragmentInputGenSupport = true;
}
virtual GrGLvoid programPathFragmentInputGen(GrGLuint program, GrGLint location,
GrGLenum genMode, GrGLint components,
const GrGLfloat *coeffs) SK_OVERRIDE;
};
GrGLPathRendering* GrGLPathRendering::Create(GrGpuGL* gpu) {
const GrGLInterface* glInterface = gpu->glInterface();
if (NULL == glInterface->fFunctions.fStencilThenCoverFillPath ||
NULL == glInterface->fFunctions.fStencilThenCoverStrokePath ||
NULL == glInterface->fFunctions.fStencilThenCoverFillPathInstanced ||
NULL == glInterface->fFunctions.fStencilThenCoverStrokePathInstanced) {
return new GrGLPathRendering(gpu);
}
if (NULL == glInterface->fFunctions.fProgramPathFragmentInputGen) {
return new GrGLPathRenderingV12(gpu);
}
return new GrGLPathRenderingV13(gpu);
}
GrGLPathRendering::GrGLPathRendering(GrGpuGL* gpu)
: fGpu(gpu) {
memset(&fCaps, 0, sizeof(fCaps));
fHWPathTexGenSettings.reset(fGpu->glCaps().maxFixedFunctionTextureCoords());
}
GrGLPathRendering::~GrGLPathRendering() {
}
void GrGLPathRendering::abandonGpuResources() {
fPathNameAllocator.reset(NULL);
}
void GrGLPathRendering::resetContext() {
fHWProjectionMatrixState.invalidate();
// we don't use the model view matrix.
GL_CALL(MatrixLoadIdentity(GR_GL_MODELVIEW));
for (int i = 0; i < fGpu->glCaps().maxFixedFunctionTextureCoords(); ++i) {
this->pathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL);
fHWPathTexGenSettings[i].fMode = GR_GL_NONE;
fHWPathTexGenSettings[i].fNumComponents = 0;
}
fHWActivePathTexGenSets = 0;
fHWPathStencilSettings.invalidate();
}
GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const SkStrokeRec& stroke) {
return SkNEW_ARGS(GrGLPath, (fGpu, inPath, stroke));
}
GrPathRange* GrGLPathRendering::createPathRange(size_t size, const SkStrokeRec& stroke) {
return SkNEW_ARGS(GrGLPathRange, (fGpu, size, stroke));
}
void GrGLPathRendering::enablePathTexGen(int unitIdx, PathTexGenComponents components,
const GrGLfloat* coefficients) {
SkASSERT(components >= kS_PathTexGenComponents &&
components <= kSTR_PathTexGenComponents);
SkASSERT(fGpu->glCaps().maxFixedFunctionTextureCoords() >= unitIdx);
if (GR_GL_OBJECT_LINEAR == fHWPathTexGenSettings[unitIdx].fMode &&
components == fHWPathTexGenSettings[unitIdx].fNumComponents &&
!memcmp(coefficients, fHWPathTexGenSettings[unitIdx].fCoefficients,
3 * components * sizeof(GrGLfloat))) {
return;
}
fGpu->setTextureUnit(unitIdx);
fHWPathTexGenSettings[unitIdx].fNumComponents = components;
this->pathTexGen(GR_GL_TEXTURE0 + unitIdx, GR_GL_OBJECT_LINEAR, components, coefficients);
memcpy(fHWPathTexGenSettings[unitIdx].fCoefficients, coefficients,
3 * components * sizeof(GrGLfloat));
}
void GrGLPathRendering::enablePathTexGen(int unitIdx, PathTexGenComponents components,
const SkMatrix& matrix) {
GrGLfloat coefficients[3 * 3];
SkASSERT(components >= kS_PathTexGenComponents &&
components <= kSTR_PathTexGenComponents);
coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
if (components >= kST_PathTexGenComponents) {
coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
}
if (components >= kSTR_PathTexGenComponents) {
coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
}
this->enablePathTexGen(unitIdx, components, coefficients);
}
void GrGLPathRendering::flushPathTexGenSettings(int numUsedTexCoordSets) {
SkASSERT(fGpu->glCaps().maxFixedFunctionTextureCoords() >= numUsedTexCoordSets);
// Only write the inactive path tex gens, since active path tex gens were
// written when they were enabled.
SkDEBUGCODE(
for (int i = 0; i < numUsedTexCoordSets; i++) {
SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
}
);
for (int i = numUsedTexCoordSets; i < fHWActivePathTexGenSets; i++) {
SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
fGpu->setTextureUnit(i);
GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
fHWPathTexGenSettings[i].fNumComponents = 0;
}
fHWActivePathTexGenSets = numUsedTexCoordSets;
}
void GrGLPathRendering::stencilPath(const GrPath* path, SkPath::FillType fill) {
GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
SkASSERT(NULL != fGpu->drawState()->getRenderTarget());
SkASSERT(NULL != fGpu->drawState()->getRenderTarget()->getStencilBuffer());
this->flushPathStencilSettings(fill);
SkASSERT(!fHWPathStencilSettings.isTwoSided());
GrGLenum fillMode =
gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
this->stencilFillPath(id, fillMode, writeMask);
}
void GrGLPathRendering::drawPath(const GrPath* path, SkPath::FillType fill) {
GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
SkASSERT(NULL != fGpu->drawState()->getRenderTarget());
SkASSERT(NULL != fGpu->drawState()->getRenderTarget()->getStencilBuffer());
SkASSERT(!fGpu->fCurrentProgram->hasVertexShader());
this->flushPathStencilSettings(fill);
SkASSERT(!fHWPathStencilSettings.isTwoSided());
const SkStrokeRec& stroke = path->getStroke();
SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(fill);
GrGLenum fillMode =
gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
if (nonInvertedFill == fill) {
if (stroke.needToApply()) {
if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
this->stencilFillPath(id, fillMode, writeMask);
}
this->stencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX);
} else {
this->stencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX);
}
} else {
if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
this->stencilFillPath(id, fillMode, writeMask);
}
if (stroke.needToApply()) {
this->stencilStrokePath(id, 0xffff, writeMask);
}
GrDrawState* drawState = fGpu->drawState();
GrDrawState::AutoViewMatrixRestore avmr;
SkRect bounds = SkRect::MakeLTRB(0, 0,
SkIntToScalar(drawState->getRenderTarget()->width()),
SkIntToScalar(drawState->getRenderTarget()->height()));
SkMatrix vmi;
// mapRect through persp matrix may not be correct
if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
vmi.mapRect(&bounds);
// theoretically could set bloat = 0, instead leave it because of matrix inversion
// precision.
SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf;
bounds.outset(bloat, bloat);
} else {
avmr.setIdentity(drawState);
}
fGpu->drawSimpleRect(bounds);
}
}
void GrGLPathRendering::drawPaths(const GrPathRange* pathRange, const uint32_t indices[], int count,
const float transforms[], PathTransformType transformsType,
SkPath::FillType fill) {
SkASSERT(fGpu->caps()->pathRenderingSupport());
SkASSERT(NULL != fGpu->drawState()->getRenderTarget());
SkASSERT(NULL != fGpu->drawState()->getRenderTarget()->getStencilBuffer());
SkASSERT(!fGpu->fCurrentProgram->hasVertexShader());
GrGLuint baseID = static_cast<const GrGLPathRange*>(pathRange)->basePathID();
this->flushPathStencilSettings(fill);
SkASSERT(!fHWPathStencilSettings.isTwoSided());
const SkStrokeRec& stroke = pathRange->getStroke();
SkPath::FillType nonInvertedFill =
SkPath::ConvertToNonInverseFillType(fill);
GrGLenum fillMode =
gr_stencil_op_to_gl_path_rendering_fill_mode(
fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
GrGLint writeMask =
fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
if (nonInvertedFill == fill) {
if (stroke.needToApply()) {
if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
this->stencilFillPathInstanced(
count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
writeMask, gXformType2GLType[transformsType],
transforms);
}
this->stencilThenCoverStrokePathInstanced(
count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff, writeMask,
GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
gXformType2GLType[transformsType], transforms);
} else {
this->stencilThenCoverFillPathInstanced(
count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode, writeMask,
GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
gXformType2GLType[transformsType], transforms);
}
} else {
if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
this->stencilFillPathInstanced(
count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
writeMask, gXformType2GLType[transformsType],
transforms);
}
if (stroke.needToApply()) {
this->stencilStrokePathInstanced(
count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff,
writeMask, gXformType2GLType[transformsType],
transforms);
}
GrDrawState* drawState = fGpu->drawState();
GrDrawState::AutoViewMatrixRestore avmr;
SkRect bounds = SkRect::MakeLTRB(0, 0,
SkIntToScalar(drawState->getRenderTarget()->width()),
SkIntToScalar(drawState->getRenderTarget()->height()));
SkMatrix vmi;
// mapRect through persp matrix may not be correct
if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
vmi.mapRect(&bounds);
// theoretically could set bloat = 0, instead leave it because of matrix inversion
// precision.
SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf;
bounds.outset(bloat, bloat);
} else {
avmr.setIdentity(drawState);
}
fGpu->drawSimpleRect(bounds);
}
}
void GrGLPathRendering::flushPathStencilSettings(SkPath::FillType fill) {
GrStencilSettings pathStencilSettings;
fGpu->getPathStencilSettingsForFillType(fill, &pathStencilSettings);
if (fHWPathStencilSettings != pathStencilSettings) {
// Just the func, ref, and mask is set here. The op and write mask are params to the call
// that draws the path to the SB (glStencilFillPath)
GrGLenum func =
GrToGLStencilFunc(pathStencilSettings.func(GrStencilSettings::kFront_Face));
this->pathStencilFunc(func, pathStencilSettings.funcRef(GrStencilSettings::kFront_Face),
pathStencilSettings.funcMask(GrStencilSettings::kFront_Face));
fHWPathStencilSettings = pathStencilSettings;
}
}
void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
const SkISize& renderTargetSize,
GrSurfaceOrigin renderTargetOrigin) {
SkASSERT(fGpu->glCaps().pathRenderingSupport());
if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
return;
}
fHWProjectionMatrixState.fViewMatrix = matrix;
fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
GrGLfloat glMatrix[4 * 4];
fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
GL_CALL(MatrixLoadf(GR_GL_PROJECTION, glMatrix));
}
// NV_path_rendering
GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
if (range > 1) {
GrGLuint name;
GL_CALL_RET(name, GenPaths(range));
return name;
}
if (NULL == fPathNameAllocator.get()) {
static const int range = 65536;
GrGLuint firstName;
GL_CALL_RET(firstName, GenPaths(range));
fPathNameAllocator.reset(SkNEW_ARGS(GrGLNameAllocator, (firstName, firstName + range)));
}
// When allocating names one at a time, pull from a client-side pool of
// available names in order to save a round trip to the GL server.
GrGLuint name = fPathNameAllocator->allocateName();
if (0 == name) {
// Our reserved path names are all in use. Fall back on GenPaths.
GL_CALL_RET(name, GenPaths(1));
}
return name;
}
GrGLvoid GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
if (range > 1) {
// It is not supported to delete names in ranges that were allocated
// individually using GrGLPathNameAllocator.
SkASSERT(NULL == fPathNameAllocator.get() ||
path + range <= fPathNameAllocator->firstName() ||
path >= fPathNameAllocator->endName());
GL_CALL(DeletePaths(path, range));
return;
}
if (NULL == fPathNameAllocator.get() ||
path < fPathNameAllocator->firstName() ||
path >= fPathNameAllocator->endName()) {
// If we aren't inside fPathNameAllocator's range then this name was
// generated by the GenPaths fallback (or else was never allocated).
GL_CALL(DeletePaths(path, 1));
return;
}
// Make the path empty to save memory, but don't free the name in the driver.
GL_CALL(PathCommands(path, 0, NULL, 0, GR_GL_FLOAT, NULL));
fPathNameAllocator->free(path);
}
GrGLvoid GrGLPathRendering::pathCommands(GrGLuint path, GrGLsizei numCommands,
const GrGLubyte *commands, GrGLsizei numCoords,
GrGLenum coordType, const GrGLvoid *coords) {
GL_CALL(PathCommands(path, numCommands, commands, numCoords, coordType, coords));
}
GrGLvoid GrGLPathRendering::pathCoords(GrGLuint path, GrGLsizei numCoords,
GrGLenum coordType, const GrGLvoid *coords) {
GL_CALL(PathCoords(path, numCoords, coordType, coords));
}
GrGLvoid GrGLPathRendering::pathParameteri(GrGLuint path, GrGLenum pname, GrGLint value) {
GL_CALL(PathParameteri(path, pname, value));
}
GrGLvoid GrGLPathRendering::pathParameterf(GrGLuint path, GrGLenum pname, GrGLfloat value) {
GL_CALL(PathParameterf(path, pname, value));
}
GrGLboolean GrGLPathRendering::isPath(GrGLuint path) {
GrGLboolean ret;
GL_CALL_RET(ret, IsPath(path));
return ret;
}
GrGLvoid GrGLPathRendering::pathStencilFunc(GrGLenum func, GrGLint ref, GrGLuint mask) {
GL_CALL(PathStencilFunc(func, ref, mask));
}
GrGLvoid GrGLPathRendering::stencilFillPath(GrGLuint path, GrGLenum fillMode, GrGLuint mask) {
// Decide how to manipulate the stencil buffer based on the fill rule.
GL_CALL(StencilFillPath(path, fillMode, mask));
}
GrGLvoid GrGLPathRendering::stencilStrokePath(GrGLuint path, GrGLint reference, GrGLuint mask) {
GL_CALL(StencilStrokePath(path, reference, mask));
}
GrGLvoid GrGLPathRendering::stencilFillPathInstanced(
GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask,
GrGLenum transformType, const GrGLfloat *transformValues) {
GL_CALL(StencilFillPathInstanced(numPaths, pathNameType, paths, pathBase,
fillMode, mask, transformType, transformValues));
}
GrGLvoid GrGLPathRendering::stencilStrokePathInstanced(
GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
GrGLuint pathBase, GrGLint reference, GrGLuint mask,
GrGLenum transformType, const GrGLfloat *transformValues) {
GL_CALL(StencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
reference, mask, transformType, transformValues));
}
GrGLvoid GrGLPathRendering::pathTexGen(GrGLenum texCoordSet, GrGLenum genMode,
GrGLint components, const GrGLfloat *coeffs) {
GL_CALL(PathTexGen(texCoordSet, genMode, components, coeffs));
}
GrGLvoid GrGLPathRendering::coverFillPath(GrGLuint path, GrGLenum coverMode) {
GL_CALL(CoverFillPath(path, coverMode));
}
GrGLvoid GrGLPathRendering::coverStrokePath(GrGLuint name, GrGLenum coverMode) {
GL_CALL(CoverStrokePath(name, coverMode));
}
GrGLvoid GrGLPathRendering::coverFillPathInstanced(
GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase,
GrGLenum coverMode, GrGLenum transformType, const GrGLfloat *transformValues) {
GL_CALL(CoverFillPathInstanced(numPaths, pathNameType, paths, pathBase,
coverMode, transformType, transformValues));
}
GrGLvoid GrGLPathRendering::coverStrokePathInstanced(
GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase,
GrGLenum coverMode, GrGLenum transformType, const GrGLfloat* transformValues) {
GL_CALL(CoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
coverMode, transformType, transformValues));
}
GrGLvoid GrGLPathRendering::stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
GrGLuint mask, GrGLenum coverMode) {
GL_CALL(StencilFillPath(path, fillMode, mask));
GL_CALL(CoverFillPath(path, coverMode));
}
GrGLvoid GrGLPathRendering::stencilThenCoverStrokePath(GrGLuint path, GrGLint reference,
GrGLuint mask, GrGLenum coverMode) {
GL_CALL(StencilStrokePath(path, reference, mask));
GL_CALL(CoverStrokePath(path, coverMode));
}
GrGLvoid GrGLPathRendering::stencilThenCoverFillPathInstanced(
GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode,
GrGLenum transformType, const GrGLfloat *transformValues) {
GL_CALL(StencilFillPathInstanced(numPaths, pathNameType, paths, pathBase,
fillMode, mask, transformType, transformValues));
GL_CALL(CoverFillPathInstanced(numPaths, pathNameType, paths, pathBase,
coverMode, transformType, transformValues));
}
GrGLvoid GrGLPathRendering::stencilThenCoverStrokePathInstanced(
GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode,
GrGLenum transformType, const GrGLfloat *transformValues) {
GL_CALL(StencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
reference, mask, transformType, transformValues));
GL_CALL(CoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
coverMode, transformType, transformValues));
}
GrGLvoid GrGLPathRendering::programPathFragmentInputGen(
GrGLuint program, GrGLint location, GrGLenum genMode,
GrGLint components, const GrGLfloat *coeffs) {
SkFAIL("ProgramPathFragmentInputGen not supported in this GL context.");
}
// NV_path_rendering v1.2
GrGLvoid GrGLPathRenderingV12::stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
GrGLuint mask, GrGLenum coverMode) {
GL_CALL(StencilThenCoverFillPath(path, fillMode, mask, coverMode));
}
GrGLvoid GrGLPathRenderingV12::stencilThenCoverStrokePath(GrGLuint path, GrGLint reference,
GrGLuint mask, GrGLenum coverMode) {
GL_CALL(StencilThenCoverStrokePath(path, reference, mask, coverMode));
}
GrGLvoid GrGLPathRenderingV12::stencilThenCoverFillPathInstanced(
GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode,
GrGLenum transformType, const GrGLfloat *transformValues) {
GL_CALL(StencilThenCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, fillMode,
mask, coverMode, transformType, transformValues));
}
GrGLvoid GrGLPathRenderingV12::stencilThenCoverStrokePathInstanced(
GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode,
GrGLenum transformType, const GrGLfloat *transformValues) {
GL_CALL(StencilThenCoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase, reference,
mask, coverMode, transformType, transformValues));
}
// NV_path_rendering v1.3
GrGLvoid GrGLPathRenderingV13::programPathFragmentInputGen(
GrGLuint program, GrGLint location, GrGLenum genMode,
GrGLint components, const GrGLfloat *coeffs) {
GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coeffs));
}