| Index: src/gpu/gl/GrGLPathRendering.cpp
|
| diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
|
| index 249d98139ad65b9d888e161ba32c7f6281a52046..53d7cf007411ab4fbc7dcd3bf55f5ac2b5915d5c 100644
|
| --- a/src/gpu/gl/GrGLPathRendering.cpp
|
| +++ b/src/gpu/gl/GrGLPathRendering.cpp
|
| @@ -6,17 +6,49 @@
|
| */
|
|
|
| #include "gl/GrGLPathRendering.h"
|
| -#include "gl/GrGLInterface.h"
|
| #include "gl/GrGLNameAllocator.h"
|
| #include "gl/GrGLUtil.h"
|
| +#include "gl/GrGpuGL.h"
|
|
|
| -#define GL_CALL(X) GR_GL_CALL(fGLInterface.get(), X)
|
| -#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(fGLInterface.get(), RET, X)
|
| +#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(const GrGLInterface* glInterface)
|
| - : GrGLPathRendering(glInterface) {
|
| + GrGLPathRenderingV12(GrGpuGL* gpu)
|
| + : GrGLPathRendering(gpu) {
|
| }
|
|
|
| virtual GrGLvoid stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
|
| @@ -35,8 +67,8 @@ public:
|
|
|
| class GrGLPathRenderingV13 : public GrGLPathRenderingV12 {
|
| public:
|
| - GrGLPathRenderingV13(const GrGLInterface* glInterface)
|
| - : GrGLPathRenderingV12(glInterface) {
|
| + GrGLPathRenderingV13(GrGpuGL* gpu)
|
| + : GrGLPathRenderingV12(gpu) {
|
| fCaps.fragmentInputGenSupport = true;
|
| }
|
|
|
| @@ -46,24 +78,26 @@ public:
|
| };
|
|
|
|
|
| -GrGLPathRendering* GrGLPathRendering::Create(const GrGLInterface* glInterface) {
|
| +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(glInterface);
|
| + return new GrGLPathRendering(gpu);
|
| }
|
|
|
| if (NULL == glInterface->fFunctions.fProgramPathFragmentInputGen) {
|
| - return new GrGLPathRenderingV12(glInterface);
|
| + return new GrGLPathRenderingV12(gpu);
|
| }
|
|
|
| - return new GrGLPathRenderingV13(glInterface);
|
| + return new GrGLPathRenderingV13(gpu);
|
| }
|
|
|
| -GrGLPathRendering::GrGLPathRendering(const GrGLInterface* glInterface)
|
| - : fGLInterface(SkRef(glInterface)) {
|
| +GrGLPathRendering::GrGLPathRendering(GrGpuGL* gpu)
|
| + : fGpu(gpu) {
|
| memset(&fCaps, 0, sizeof(fCaps));
|
| + fHWPathTexGenSettings.reset(fGpu->glCaps().maxFixedFunctionTextureCoords());
|
| }
|
|
|
| GrGLPathRendering::~GrGLPathRendering() {
|
| @@ -73,6 +107,281 @@ 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) {
|
| @@ -156,6 +465,7 @@ GrGLvoid GrGLPathRendering::pathStencilFunc(GrGLenum func, GrGLint ref, GrGLuint
|
| }
|
|
|
| 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));
|
| }
|
|
|
|
|