aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar cdalton <cdalton@nvidia.com>2014-07-29 15:25:51 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-07-29 15:25:51 -0700
commitc8f520466701a14cf2fb86d3f2d3c70983cb4518 (patch)
treeba37430ec889b9664f5f2f4d59f1c618ff7e72d9 /src
parenta14da251c29a8f9e6db37648e2c41c8bbf0af19b (diff)
Incorporate glStencilThenCover* nvpr methods
Adds the glStencilThenCover* nvpr methods to GrGLInterface and starts using them. When drawing multible paths, this will make it so we only have to send the index/transform data once. It will also allow the driver to save time internally. The glStencilThenCover* methods are a newer addition, so they aren't available on every driver. In the event that they are not present, we emulate them using the existing glStencil*/glCover* methods. BUG=skia: R=markkilgard@gmail.com, bsalomon@google.com Author: cdalton@nvidia.com Review URL: https://codereview.chromium.org/423173004
Diffstat (limited to 'src')
-rw-r--r--src/gpu/gl/GrGLAssembleGLESInterface.h4
-rw-r--r--src/gpu/gl/GrGLAssembleInterface.cpp115
-rw-r--r--src/gpu/gl/GrGLInterface.cpp6
-rw-r--r--src/gpu/gl/GrGpuGL.cpp59
4 files changed, 159 insertions, 25 deletions
diff --git a/src/gpu/gl/GrGLAssembleGLESInterface.h b/src/gpu/gl/GrGLAssembleGLESInterface.h
index d3ebebd756..8162c2d9b5 100644
--- a/src/gpu/gl/GrGLAssembleGLESInterface.h
+++ b/src/gpu/gl/GrGLAssembleGLESInterface.h
@@ -276,6 +276,10 @@ static const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get
GET_PROC_SUFFIX(CoverStrokePath, NV);
GET_PROC_SUFFIX(CoverFillPathInstanced, NV);
GET_PROC_SUFFIX(CoverStrokePathInstanced, NV);
+ GET_PROC_SUFFIX(StencilThenCoverFillPath, NV);
+ GET_PROC_SUFFIX(StencilThenCoverStrokePath, NV);
+ GET_PROC_SUFFIX(StencilThenCoverFillPathInstanced, NV);
+ GET_PROC_SUFFIX(StencilThenCoverStrokePathInstanced, NV);
GET_PROC_SUFFIX(ProgramPathFragmentInputGen, NV);
}
diff --git a/src/gpu/gl/GrGLAssembleInterface.cpp b/src/gpu/gl/GrGLAssembleInterface.cpp
index c6b3f93793..4ae50ba391 100644
--- a/src/gpu/gl/GrGLAssembleInterface.cpp
+++ b/src/gpu/gl/GrGLAssembleInterface.cpp
@@ -14,6 +14,12 @@
#define GET_PROC_SUFFIX(F, S) functions->f ## F = (GrGL ## F ## Proc) get(ctx, "gl" #F #S)
#define GET_PROC_LOCAL(F) GrGL ## F ## Proc F = (GrGL ## F ## Proc) get(ctx, "gl" #F)
+// The glStencilThenCover* methods are a new addition to NV_path_rendering. They
+// aren't available on all drivers. In the event that they are not present, this
+// function can be used to add methods to the given GrGLInterface that emulate
+// them using the existing glStencil*/glCover* methods.
+static void emulate_nvpr_stencil_then_cover(GrGLInterface*);
+
const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) {
GET_PROC_LOCAL(GetString);
GET_PROC_LOCAL(GetStringi);
@@ -239,7 +245,18 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) {
GET_PROC_SUFFIX(CoverStrokePath, NV);
GET_PROC_SUFFIX(CoverFillPathInstanced, NV);
GET_PROC_SUFFIX(CoverStrokePathInstanced, NV);
+ GET_PROC_SUFFIX(StencilThenCoverFillPath, NV);
+ GET_PROC_SUFFIX(StencilThenCoverStrokePath, NV);
+ GET_PROC_SUFFIX(StencilThenCoverFillPathInstanced, NV);
+ GET_PROC_SUFFIX(StencilThenCoverStrokePathInstanced, NV);
GET_PROC_SUFFIX(ProgramPathFragmentInputGen, NV);
+
+ if (NULL == interface->fFunctions.fStencilThenCoverFillPath ||
+ NULL == interface->fFunctions.fStencilThenCoverStrokePath ||
+ NULL == interface->fFunctions.fStencilThenCoverFillPathInstanced ||
+ NULL == interface->fFunctions.fStencilThenCoverFillPathInstanced) {
+ emulate_nvpr_stencil_then_cover(interface);
+ }
}
if (extensions.has("GL_EXT_debug_marker")) {
@@ -266,3 +283,101 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) {
return interface;
}
+
+static GrGLStencilFillPathProc gStencilFillPath;
+static GrGLCoverFillPathProc gCoverFillPath;
+static GrGLvoid GR_GL_FUNCTION_TYPE stencil_then_cover_fill_path(
+ GrGLuint path, GrGLenum fillMode,
+ GrGLuint mask, GrGLenum coverMode) {
+ gStencilFillPath(path, fillMode, mask);
+ gCoverFillPath(path, coverMode);
+}
+
+
+static GrGLStencilStrokePathProc gStencilStrokePath;
+static GrGLCoverStrokePathProc gCoverStrokePath;
+static GrGLvoid GR_GL_FUNCTION_TYPE stencil_then_cover_stroke_path(
+ GrGLuint path, GrGLint reference,
+ GrGLuint mask, GrGLenum coverMode) {
+ gStencilStrokePath(path, reference, mask);
+ gCoverStrokePath(path, coverMode);
+}
+
+static GrGLStencilFillPathInstancedProc gStencilFillPathInstanced;
+static GrGLCoverFillPathInstancedProc gCoverFillPathInstanced;
+static GrGLvoid GR_GL_FUNCTION_TYPE stencil_then_cover_fill_path_instanced(
+ GrGLsizei numPaths, GrGLenum pathNameType,
+ const GrGLvoid *paths, GrGLuint pathBase,
+ GrGLenum fillMode, GrGLuint mask,
+ GrGLenum coverMode, GrGLenum transformType,
+ const GrGLfloat *transformValues) {
+ gStencilFillPathInstanced(numPaths, pathNameType, paths, pathBase,
+ fillMode, mask, transformType, transformValues);
+ gCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase,
+ coverMode, transformType, transformValues);
+}
+
+static GrGLStencilStrokePathInstancedProc gStencilStrokePathInstanced;
+static GrGLCoverStrokePathInstancedProc gCoverStrokePathInstanced;
+static GrGLvoid GR_GL_FUNCTION_TYPE stencil_then_cover_stroke_path_instanced(
+ GrGLsizei numPaths, GrGLenum pathNameType,
+ const GrGLvoid *paths, GrGLuint pathBase,
+ GrGLint reference, GrGLuint mask,
+ GrGLenum coverMode, GrGLenum transformType,
+ const GrGLfloat *transformValues) {
+ gStencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
+ reference, mask, transformType, transformValues);
+ gCoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
+ coverMode, transformType, transformValues);
+}
+
+static void emulate_nvpr_stencil_then_cover(GrGLInterface* interface) {
+ if (NULL == gStencilFillPath) {
+ gStencilFillPath = (GrGLStencilFillPathProc)interface->fFunctions.fStencilFillPath;
+ }
+ if (NULL == gCoverFillPath) {
+ gCoverFillPath = (GrGLCoverFillPathProc)interface->fFunctions.fCoverFillPath;
+ }
+ if (NULL == gStencilStrokePath) {
+ gStencilStrokePath = (GrGLStencilStrokePathProc)interface->fFunctions.fStencilStrokePath;
+ }
+ if (NULL == gCoverStrokePath) {
+ gCoverStrokePath = (GrGLCoverStrokePathProc)interface->fFunctions.fCoverStrokePath;
+ }
+ if (NULL == gStencilFillPathInstanced) {
+ gStencilFillPathInstanced = (GrGLStencilFillPathInstancedProc)
+ interface->fFunctions.fStencilFillPathInstanced;
+ }
+ if (NULL == gCoverFillPathInstanced) {
+ gCoverFillPathInstanced = (GrGLCoverFillPathInstancedProc)
+ interface->fFunctions.fCoverFillPathInstanced;
+ }
+ if (NULL == gStencilStrokePathInstanced) {
+ gStencilStrokePathInstanced = (GrGLStencilStrokePathInstancedProc)
+ interface->fFunctions.fStencilStrokePathInstanced;
+ }
+ if (NULL == gCoverStrokePathInstanced) {
+ gCoverStrokePathInstanced = (GrGLCoverStrokePathInstancedProc)
+ interface->fFunctions.fCoverStrokePathInstanced;
+ }
+
+ if (interface->fFunctions.fStencilFillPath != gStencilFillPath ||
+ interface->fFunctions.fCoverFillPath != gCoverFillPath ||
+ interface->fFunctions.fStencilStrokePath != gStencilStrokePath ||
+ interface->fFunctions.fCoverStrokePath != gCoverStrokePath ||
+ interface->fFunctions.fStencilFillPathInstanced != gStencilFillPathInstanced ||
+ interface->fFunctions.fCoverFillPathInstanced != gCoverFillPathInstanced ||
+ interface->fFunctions.fStencilStrokePathInstanced != gStencilStrokePathInstanced ||
+ interface->fFunctions.fCoverStrokePathInstanced != gCoverStrokePathInstanced) {
+ // While not every windowing system requires GetProcAddress to return
+ // the same addresses in different contexts, it is guaranteed to do so
+ // in any context that supports NV_path_rendering.
+ SkFAIL("GetProcAddress returned different addresses for the same nvpr functions");
+ return;
+ }
+
+ interface->fFunctions.fStencilThenCoverFillPath = &stencil_then_cover_fill_path;
+ interface->fFunctions.fStencilThenCoverStrokePath = &stencil_then_cover_stroke_path;
+ interface->fFunctions.fStencilThenCoverFillPathInstanced = &stencil_then_cover_fill_path_instanced;
+ interface->fFunctions.fStencilThenCoverStrokePathInstanced = &stencil_then_cover_stroke_path_instanced;
+}
diff --git a/src/gpu/gl/GrGLInterface.cpp b/src/gpu/gl/GrGLInterface.cpp
index 823b73efa3..e9ba32ed24 100644
--- a/src/gpu/gl/GrGLInterface.cpp
+++ b/src/gpu/gl/GrGLInterface.cpp
@@ -467,7 +467,11 @@ bool GrGLInterface::validate() const {
NULL == fFunctions.fCoverFillPath ||
NULL == fFunctions.fCoverStrokePath ||
NULL == fFunctions.fCoverFillPathInstanced ||
- NULL == fFunctions.fCoverStrokePathInstanced) {
+ NULL == fFunctions.fCoverStrokePathInstanced ||
+ NULL == fFunctions.fStencilThenCoverFillPath ||
+ NULL == fFunctions.fStencilThenCoverStrokePath ||
+ NULL == fFunctions.fStencilThenCoverFillPathInstanced ||
+ NULL == fFunctions.fStencilThenCoverStrokePathInstanced) {
RETURN_FALSE_INTERFACE
}
// Currently ProgramPathFragmentInputGen is not used on
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index f079abce49..404e7abdbd 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -1894,20 +1894,23 @@ void GrGpuGL::onGpuDrawPath(const GrPath* path, SkPath::FillType fill) {
gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
- if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
- GL_CALL(StencilFillPath(id, fillMode, writeMask));
- }
- if (stroke.needToApply()) {
- GL_CALL(StencilStrokePath(id, 0xffff, writeMask));
- }
-
if (nonInvertedFill == fill) {
if (stroke.needToApply()) {
- GL_CALL(CoverStrokePath(id, GR_GL_BOUNDING_BOX));
+ if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
+ GL_CALL(StencilFillPath(id, fillMode, writeMask));
+ }
+ GL_CALL(StencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX));
} else {
- GL_CALL(CoverFillPath(id, GR_GL_BOUNDING_BOX));
+ GL_CALL(StencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX));
}
} else {
+ if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
+ GL_CALL(StencilFillPath(id, fillMode, writeMask));
+ }
+ if (stroke.needToApply()) {
+ GL_CALL(StencilStrokePath(id, 0xffff, writeMask));
+ }
+
GrDrawState* drawState = this->drawState();
GrDrawState::AutoViewMatrixRestore avmr;
SkRect bounds = SkRect::MakeLTRB(0, 0,
@@ -1953,30 +1956,38 @@ void GrGpuGL::onGpuDrawPaths(const GrPathRange* pathRange,
GrGLint writeMask =
fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
- if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
- GL_CALL(StencilFillPathInstanced(count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
- writeMask, gXformType2GLType[transformsType],
- transforms));
- }
- if (stroke.needToApply()) {
- GL_CALL(StencilStrokePathInstanced(count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff,
- writeMask, gXformType2GLType[transformsType],
- transforms));
- }
-
if (nonInvertedFill == fill) {
if (stroke.needToApply()) {
- GL_CALL(CoverStrokePathInstanced(
- count, GR_GL_UNSIGNED_INT, indices, baseID,
+ if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
+ GL_CALL(StencilFillPathInstanced(
+ count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
+ writeMask, gXformType2GLType[transformsType],
+ transforms));
+ }
+ GL_CALL(StencilThenCoverStrokePathInstanced(
+ count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff, writeMask,
GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
gXformType2GLType[transformsType], transforms));
} else {
- GL_CALL(CoverFillPathInstanced(
- count, GR_GL_UNSIGNED_INT, indices, baseID,
+ GL_CALL(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()) {
+ GL_CALL(StencilFillPathInstanced(
+ count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
+ writeMask, gXformType2GLType[transformsType],
+ transforms));
+ }
+ if (stroke.needToApply()) {
+ GL_CALL(StencilStrokePathInstanced(
+ count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff,
+ writeMask, gXformType2GLType[transformsType],
+ transforms));
+ }
+
GrDrawState* drawState = this->drawState();
GrDrawState::AutoViewMatrixRestore avmr;
SkRect bounds = SkRect::MakeLTRB(0, 0,