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
This commit is contained in:
parent
a14da251c2
commit
c8f5204667
@ -245,6 +245,10 @@ extern "C" {
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCoverStrokePathProc)(GrGLuint name, GrGLenum coverMode);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCoverFillPathInstancedProc)(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat *transformValues);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCoverStrokePathInstancedProc)(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat* transformValues);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilThenCoverFillPathProc)(GrGLuint path, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilThenCoverStrokePathProc)(GrGLuint path, GrGLint reference, GrGLuint mask, GrGLenum coverMode);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilThenCoverFillPathInstancedProc)(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat *transformValues);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilThenCoverStrokePathInstancedProc)(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat *transformValues);
|
||||
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLProgramPathFragmentInputGenProc)(GrGLuint program, GrGLint location, GrGLenum genMode, GrGLint components,const GrGLfloat *coeffs);
|
||||
} // extern "C"
|
||||
|
@ -335,6 +335,10 @@ public:
|
||||
GLPtr<GrGLCoverStrokePathProc> fCoverStrokePath;
|
||||
GLPtr<GrGLCoverFillPathInstancedProc> fCoverFillPathInstanced;
|
||||
GLPtr<GrGLCoverStrokePathInstancedProc> fCoverStrokePathInstanced;
|
||||
GLPtr<GrGLStencilThenCoverFillPathProc> fStencilThenCoverFillPath;
|
||||
GLPtr<GrGLStencilThenCoverStrokePathProc> fStencilThenCoverStrokePath;
|
||||
GLPtr<GrGLStencilThenCoverFillPathInstancedProc> fStencilThenCoverFillPathInstanced;
|
||||
GLPtr<GrGLStencilThenCoverStrokePathInstancedProc> fStencilThenCoverStrokePathInstanced;
|
||||
GLPtr<GrGLProgramPathFragmentInputGenProc> fProgramPathFragmentInputGen;
|
||||
} fFunctions;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user