Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(340)

Unified Diff: src/gpu/gl/GrGLPathRendering.cpp

Issue 452823002: Separate GL path rendering state from GrGpuGL to GrGLPathRendering (Closed) Base URL: https://skia.googlesource.com/skia.git@00xx-cherrypick-pathrendering-class
Patch Set: beautify Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/gpu/gl/GrGLPathRendering.cpp
diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
index 249d98139ad65b9d888e161ba32c7f6281a52046..00848bd9ed5e45f89d47a2861d86e799613ed98b 100644
--- a/src/gpu/gl/GrGLPathRendering.cpp
+++ b/src/gpu/gl/GrGLPathRendering.cpp
@@ -9,14 +9,47 @@
#include "gl/GrGLInterface.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(fGLInterface.get(), X)
#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(fGLInterface.get(), 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, const GrGLInterface* glInterface)
+ : GrGLPathRendering(gpu, glInterface) {
}
virtual GrGLvoid stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
@@ -35,8 +68,8 @@ public:
class GrGLPathRenderingV13 : public GrGLPathRenderingV12 {
public:
- GrGLPathRenderingV13(const GrGLInterface* glInterface)
- : GrGLPathRenderingV12(glInterface) {
+ GrGLPathRenderingV13(GrGpuGL* gpu, const GrGLInterface* glInterface)
+ : GrGLPathRenderingV12(gpu, glInterface) {
fCaps.fragmentInputGenSupport = true;
}
@@ -46,24 +79,26 @@ public:
};
-GrGLPathRendering* GrGLPathRendering::Create(const GrGLInterface* glInterface) {
+GrGLPathRendering* GrGLPathRendering::Create(GrGpuGL* gpu, const GrGLInterface* 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, glInterface);
}
if (NULL == glInterface->fFunctions.fProgramPathFragmentInputGen) {
- return new GrGLPathRenderingV12(glInterface);
+ return new GrGLPathRenderingV12(gpu, glInterface);
}
- return new GrGLPathRenderingV13(glInterface);
+ return new GrGLPathRenderingV13(gpu, glInterface);
}
-GrGLPathRendering::GrGLPathRendering(const GrGLInterface* glInterface)
- : fGLInterface(SkRef(glInterface)) {
+GrGLPathRendering::GrGLPathRendering(GrGpuGL* gpu, const GrGLInterface* glInterface)
+ : fGpu(gpu),
+ fGLInterface(SkRef(glInterface)) {
memset(&fCaps, 0, sizeof(fCaps));
+ fHWPathTexGenSettings.reset(fGpu->glCaps().maxFixedFunctionTextureCoords());
}
GrGLPathRendering::~GrGLPathRendering() {
@@ -73,6 +108,277 @@ void GrGLPathRendering::abandonGpuResources() {
fPathNameAllocator.reset(NULL);
}
+void GrGLPathRendering::onResetContext() {
+ 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);
+
+ 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);
+ const SkStrokeRec& stroke = path->getStroke();
+
+ SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(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);
+
+ 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);
+ const SkStrokeRec& stroke = pathRange->getStroke();
+
+ SkPath::FillType nonInvertedFill =
+ SkPath::ConvertToNonInverseFillType(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);
+
+ 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 +462,9 @@ 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.
+ SkASSERT(!fHWPathStencilSettings.isTwoSided());
Chris Dalton 2014/08/14 16:22:09 Do we need similar checks in stencil(Then)Cover(St
Kimmo Kinnunen 2014/08/15 06:19:26 Done.
+
GL_CALL(StencilFillPath(path, fillMode, mask));
}

Powered by Google App Engine
This is Rietveld 408576698