diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/gpu/GrContextFactory.cpp | 17 | ||||
-rw-r--r-- | src/gpu/gl/GrGLAssembleInterface.cpp | 5 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.cpp | 45 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.h | 1 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.h | 3 | ||||
-rw-r--r-- | src/gpu/gl/GrGLInterface.cpp | 32 | ||||
-rw-r--r-- | src/gpu/gl/GrGLPathRendering.cpp | 78 | ||||
-rw-r--r-- | src/gpu/gl/GrGLPathRendering.h | 33 |
8 files changed, 151 insertions, 63 deletions
diff --git a/src/gpu/GrContextFactory.cpp b/src/gpu/GrContextFactory.cpp index f62c6fe1d6..7df19177eb 100755 --- a/src/gpu/GrContextFactory.cpp +++ b/src/gpu/GrContextFactory.cpp @@ -17,7 +17,7 @@ #endif #include "gl/SkGLContext.h" #include "gl/SkNullGLContext.h" -#include "GrCaps.h" + GrContext* GrContextFactory::get(GLContextType type, GrGLStandard forcedGpuAPI) { for (int i = 0; i < fContexts.count(); ++i) { @@ -60,9 +60,13 @@ GrContext* GrContextFactory::get(GLContextType type, GrGLStandard forcedGpuAPI) SkASSERT(glCtx->isValid()); - // Block NVPR from non-NVPR types. + // Ensure NVPR is available for the NVPR type and block it from other types. SkAutoTUnref<const GrGLInterface> glInterface(SkRef(glCtx->gl())); - if (kNVPR_GLContextType != type) { + if (kNVPR_GLContextType == type) { + if (!glInterface->hasExtension("GL_NV_path_rendering")) { + return NULL; + } + } else { glInterface.reset(GrGLInterfaceRemoveNVPR(glInterface)); if (!glInterface) { return NULL; @@ -75,13 +79,6 @@ GrContext* GrContextFactory::get(GLContextType type, GrGLStandard forcedGpuAPI) if (!grCtx.get()) { return NULL; } - // Ensure path rendering support is available for the NVPR type - if (kNVPR_GLContextType == type) { - if (!grCtx->caps()->shaderCaps()->pathRenderingSupport()) { - return NULL; - } - } - GPUContext& ctx = fContexts.push_back(); ctx.fGLContext = glCtx.get(); ctx.fGLContext->ref(); diff --git a/src/gpu/gl/GrGLAssembleInterface.cpp b/src/gpu/gl/GrGLAssembleInterface.cpp index 3f66c0388a..1fe53ebc3e 100644 --- a/src/gpu/gl/GrGLAssembleInterface.cpp +++ b/src/gpu/gl/GrGLAssembleInterface.cpp @@ -273,6 +273,7 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) { GET_PROC_SUFFIX(MatrixLoadf, EXT); GET_PROC_SUFFIX(MatrixLoadIdentity, EXT); GET_PROC_SUFFIX(PathCommands, NV); + GET_PROC_SUFFIX(PathCoords, NV); GET_PROC_SUFFIX(PathParameteri, NV); GET_PROC_SUFFIX(PathParameterf, NV); GET_PROC_SUFFIX(GenPaths, NV); @@ -283,14 +284,17 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) { GET_PROC_SUFFIX(StencilStrokePath, NV); GET_PROC_SUFFIX(StencilFillPathInstanced, NV); GET_PROC_SUFFIX(StencilStrokePathInstanced, NV); + GET_PROC_SUFFIX(PathTexGen, NV); GET_PROC_SUFFIX(CoverFillPath, NV); GET_PROC_SUFFIX(CoverStrokePath, NV); GET_PROC_SUFFIX(CoverFillPathInstanced, NV); GET_PROC_SUFFIX(CoverStrokePathInstanced, NV); + // NV_path_rendering v1.2 (These methods may not be present) GET_PROC_SUFFIX(StencilThenCoverFillPath, NV); GET_PROC_SUFFIX(StencilThenCoverStrokePath, NV); GET_PROC_SUFFIX(StencilThenCoverFillPathInstanced, NV); GET_PROC_SUFFIX(StencilThenCoverStrokePathInstanced, NV); + // NV_path_rendering v1.3 (These methods may not be present) GET_PROC_SUFFIX(ProgramPathFragmentInputGen, NV); } @@ -678,6 +682,7 @@ const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get) { GET_PROC_SUFFIX(MatrixLoadf, EXT); GET_PROC_SUFFIX(MatrixLoadIdentity, EXT); GET_PROC_SUFFIX(PathCommands, NV); + GET_PROC_SUFFIX(PathCoords, NV); GET_PROC_SUFFIX(PathParameteri, NV); GET_PROC_SUFFIX(PathParameterf, NV); GET_PROC_SUFFIX(GenPaths, NV); diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 539212c3a5..feb45eab88 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -279,7 +279,21 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, * GrShaderCaps fields **************************************************************************/ - glslCaps->fPathRenderingSupport = this->hasPathRenderingSupport(ctxInfo, gli); + glslCaps->fPathRenderingSupport = ctxInfo.hasExtension("GL_NV_path_rendering"); + + if (glslCaps->fPathRenderingSupport) { + if (kGL_GrGLStandard == standard) { + // We only support v1.3+ of GL_NV_path_rendering which allows us to + // set individual fragment inputs with ProgramPathFragmentInputGen. The API + // additions are detected by checking the existence of the function. + glslCaps->fPathRenderingSupport = ((ctxInfo.version() >= GR_GL_VER(4, 3) || + ctxInfo.hasExtension("GL_ARB_program_interface_query")) && + gli->fFunctions.fProgramPathFragmentInputGen); + } + else { + glslCaps->fPathRenderingSupport = ctxInfo.version() >= GR_GL_VER(3, 1); + } + } // For now these two are equivalent but we could have dst read in shader via some other method glslCaps->fDstReadInShaderSupport = glslCaps->fFBFetchSupport; @@ -463,35 +477,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, glslCaps->applyOptionsOverrides(contextOptions); } -bool GrGLCaps::hasPathRenderingSupport(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) { - if (!ctxInfo.hasExtension("GL_NV_path_rendering")) { - return false; - } - if (kGL_GrGLStandard == ctxInfo.standard()) { - if (ctxInfo.version() < GR_GL_VER(4, 3) && - !ctxInfo.hasExtension("GL_ARB_program_interface_query")) { - return false; - } - } else { - if (ctxInfo.version() < GR_GL_VER(3, 1)) { - return false; - } - } - // We only support v1.3+ of GL_NV_path_rendering which allows us to - // set individual fragment inputs with ProgramPathFragmentInputGen. The API - // additions are detected by checking the existence of the function. - // We also use *Then* functions that not all drivers might have. Check - // them for consistency. - if (NULL == gli->fFunctions.fStencilThenCoverFillPath || - NULL == gli->fFunctions.fStencilThenCoverStrokePath || - NULL == gli->fFunctions.fStencilThenCoverFillPathInstanced || - NULL == gli->fFunctions.fStencilThenCoverStrokePathInstanced || - NULL == gli->fFunctions.fProgramPathFragmentInputGen) { - return false; - } - return true; -} - void GrGLCaps::initConfigRenderableTable(const GrGLContextInfo& ctxInfo) { // OpenGL < 3.0 // no support for render targets unless the GL_ARB_framebuffer_object diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index ac90aa1db6..1e07a76ed5 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -281,7 +281,6 @@ public: private: void init(const GrContextOptions&, const GrGLContextInfo&, const GrGLInterface*); - bool hasPathRenderingSupport(const GrGLContextInfo&, const GrGLInterface*); /** * Maintains a bit per GrPixelConfig. It is used to avoid redundantly diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index e5cd7a9a9d..4872db7309 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -54,7 +54,8 @@ public: void discard(GrRenderTarget*) override; - // Used by GrGLProgram to configure OpenGL state. + // Used by GrGLProgram and GrGLPathTexGenProgramEffects to configure OpenGL + // state. void bindTexture(int unitIdx, const GrTextureParams& params, GrGLTexture* texture); // GrGpu overrides diff --git a/src/gpu/gl/GrGLInterface.cpp b/src/gpu/gl/GrGLInterface.cpp index 56f1e59275..3d44f6d602 100644 --- a/src/gpu/gl/GrGLInterface.cpp +++ b/src/gpu/gl/GrGLInterface.cpp @@ -40,6 +40,7 @@ const GrGLInterface* GrGLInterfaceRemoveNVPR(const GrGLInterface* interface) { newInterface->fExtensions.remove("GL_NV_path_rendering"); newInterface->fFunctions.fPathCommands = NULL; + newInterface->fFunctions.fPathCoords = NULL; newInterface->fFunctions.fPathParameteri = NULL; newInterface->fFunctions.fPathParameterf = NULL; newInterface->fFunctions.fGenPaths = NULL; @@ -50,6 +51,7 @@ const GrGLInterface* GrGLInterfaceRemoveNVPR(const GrGLInterface* interface) { newInterface->fFunctions.fStencilStrokePath = NULL; newInterface->fFunctions.fStencilFillPathInstanced = NULL; newInterface->fFunctions.fStencilStrokePathInstanced = NULL; + newInterface->fFunctions.fPathTexGen = NULL; newInterface->fFunctions.fCoverFillPath = NULL; newInterface->fFunctions.fCoverStrokePath = NULL; newInterface->fFunctions.fCoverFillPathInstanced = NULL; @@ -487,6 +489,7 @@ bool GrGLInterface::validate() const { if (NULL == fFunctions.fMatrixLoadf || NULL == fFunctions.fMatrixLoadIdentity || NULL == fFunctions.fPathCommands || + NULL == fFunctions.fPathCoords || NULL == fFunctions.fPathParameteri || NULL == fFunctions.fPathParameterf || NULL == fFunctions.fGenPaths || @@ -500,21 +503,24 @@ bool GrGLInterface::validate() const { NULL == fFunctions.fCoverFillPath || NULL == fFunctions.fCoverStrokePath || NULL == fFunctions.fCoverFillPathInstanced || - NULL == fFunctions.fCoverStrokePathInstanced -#if 0 - // List of functions that Skia uses, but which have been added since the initial release - // of NV_path_rendering driver. We do not want to fail interface validation due to - // missing features, we will just not use the extension. - // Update this list -> update GrGLCaps::hasPathRenderingSupport too. - || NULL == fFunctions.fStencilThenCoverFillPath || - NULL == fFunctions.fStencilThenCoverStrokePath || - NULL == fFunctions.fStencilThenCoverFillPathInstanced || - NULL == fFunctions.fStencilThenCoverStrokePathInstanced || - NULL == fFunctions.fProgramPathFragmentInputGen -#endif - ) { + NULL == fFunctions.fCoverStrokePathInstanced) { RETURN_FALSE_INTERFACE } + if (kGL_GrGLStandard == fStandard) { + // Some methods only exist on desktop + if (NULL == fFunctions.fPathTexGen) { + RETURN_FALSE_INTERFACE + } + } else { + // All additions through v1.3 exist on GLES + if (NULL == fFunctions.fStencilThenCoverFillPath || + NULL == fFunctions.fStencilThenCoverStrokePath || + NULL == fFunctions.fStencilThenCoverFillPathInstanced || + NULL == fFunctions.fStencilThenCoverStrokePathInstanced || + NULL == fFunctions.fProgramPathFragmentInputGen) { + RETURN_FALSE_INTERFACE + } + } } if (fExtensions.has("GL_EXT_raster_multisample")) { diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp index ffdbbdab26..eb9f5a86f7 100644 --- a/src/gpu/gl/GrGLPathRendering.cpp +++ b/src/gpu/gl/GrGLPathRendering.cpp @@ -61,6 +61,16 @@ static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) { GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu) : GrPathRendering(gpu) { + const GrGLInterface* glInterface = gpu->glInterface(); + fCaps.stencilThenCoverSupport = + NULL != glInterface->fFunctions.fStencilThenCoverFillPath && + NULL != glInterface->fFunctions.fStencilThenCoverStrokePath && + NULL != glInterface->fFunctions.fStencilThenCoverFillPathInstanced && + NULL != glInterface->fFunctions.fStencilThenCoverStrokePathInstanced; + fCaps.fragmentInputGenSupport = + NULL != glInterface->fFunctions.fProgramPathFragmentInputGen; + + SkASSERT(fCaps.fragmentInputGenSupport); } GrGLPathRendering::~GrGLPathRendering() { @@ -75,6 +85,7 @@ void GrGLPathRendering::resetContext() { // we don't use the model view matrix. GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW)); + SkASSERT(fCaps.fragmentInputGenSupport); fHWPathStencilSettings.invalidate(); } @@ -134,11 +145,9 @@ void GrGLPathRendering::onDrawPath(const DrawPathArgs& args, const GrPath* path) if (glPath->shouldFill()) { GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask)); } - GL_CALL(StencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask, - GR_GL_BOUNDING_BOX)); + this->stencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask, GR_GL_BOUNDING_BOX); } else { - GL_CALL(StencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask, - GR_GL_BOUNDING_BOX)); + this->stencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask, GR_GL_BOUNDING_BOX); } } @@ -168,21 +177,22 @@ void GrGLPathRendering::onDrawPaths(const DrawPathArgs& args, const GrPathRange* fillMode, writeMask, gXformType2GLType[transformType], transformValues)); } - GL_CALL(StencilThenCoverStrokePathInstanced( + this->stencilThenCoverStrokePathInstanced( count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(), 0xffff, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES, - gXformType2GLType[transformType], transformValues)); + gXformType2GLType[transformType], transformValues); } else { - GL_CALL(StencilThenCoverFillPathInstanced( + this->stencilThenCoverFillPathInstanced( count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(), fillMode, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES, - gXformType2GLType[transformType], transformValues)); + gXformType2GLType[transformType], transformValues); } } void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location, GrGLenum genMode, GrGLint components, const SkMatrix& matrix) { + SkASSERT(caps().fragmentInputGenSupport); GrGLfloat coefficients[3 * 3]; SkASSERT(components >= 1 && components <= 3); @@ -290,6 +300,58 @@ void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stenci } } +inline void GrGLPathRendering::stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode, + GrGLuint mask, GrGLenum coverMode) { + if (caps().stencilThenCoverSupport) { + GL_CALL(StencilThenCoverFillPath(path, fillMode, mask, coverMode)); + return; + } + GL_CALL(StencilFillPath(path, fillMode, mask)); + GL_CALL(CoverFillPath(path, coverMode)); +} + +inline void GrGLPathRendering::stencilThenCoverStrokePath(GrGLuint path, GrGLint reference, + GrGLuint mask, GrGLenum coverMode) { + if (caps().stencilThenCoverSupport) { + GL_CALL(StencilThenCoverStrokePath(path, reference, mask, coverMode)); + return; + } + GL_CALL(StencilStrokePath(path, reference, mask)); + GL_CALL(CoverStrokePath(path, coverMode)); +} + +inline void GrGLPathRendering::stencilThenCoverFillPathInstanced( + GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, + GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode, + GrGLenum transformType, const GrGLfloat *transformValues) { + if (caps().stencilThenCoverSupport) { + GL_CALL(StencilThenCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, fillMode, + mask, coverMode, transformType, transformValues)); + return; + } + GL_CALL(StencilFillPathInstanced(numPaths, pathNameType, paths, pathBase, + fillMode, mask, transformType, transformValues)); + GL_CALL(CoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, + coverMode, transformType, transformValues)); +} + +inline void GrGLPathRendering::stencilThenCoverStrokePathInstanced( + GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, + GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode, + GrGLenum transformType, const GrGLfloat *transformValues) { + if (caps().stencilThenCoverSupport) { + GL_CALL(StencilThenCoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase, + reference, mask, coverMode, transformType, + transformValues)); + return; + } + + GL_CALL(StencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase, + reference, mask, transformType, transformValues)); + GL_CALL(CoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase, + coverMode, transformType, transformValues)); +} + inline GrGLGpu* GrGLPathRendering::gpu() { return static_cast<GrGLGpu*>(fGpu); } diff --git a/src/gpu/gl/GrGLPathRendering.h b/src/gpu/gl/GrGLPathRendering.h index 86cf1b1698..20fd4967b7 100644 --- a/src/gpu/gl/GrGLPathRendering.h +++ b/src/gpu/gl/GrGLPathRendering.h @@ -65,8 +65,35 @@ protected: void onDrawPaths(const DrawPathArgs&, const GrPathRange*, const void* indices, PathIndexType, const float transformValues[], PathTransformType, int count) override; private: + /** + * Mark certain functionality as not supported if the driver version is too + * old and a backup implementation is not practical. + */ + struct Caps { + bool stencilThenCoverSupport : 1; + bool fragmentInputGenSupport : 1; + }; + const Caps& caps() const { return fCaps; } + void flushPathStencilSettings(const GrStencilSettings&); + // NV_path_rendering v1.2 + void stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode, + GrGLuint mask, GrGLenum coverMode); + + void stencilThenCoverStrokePath(GrGLuint path, GrGLint reference, + GrGLuint mask, GrGLenum coverMode); + + void stencilThenCoverFillPathInstanced( + GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, + GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode, + GrGLenum transformType, const GrGLfloat *transformValues); + + void stencilThenCoverStrokePathInstanced( + GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, + GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode, + GrGLenum transformType, const GrGLfloat *transformValues); + struct MatrixState { SkMatrix fViewMatrix; SkISize fRenderTargetSize; @@ -101,8 +128,14 @@ private: GrGLGpu* gpu(); SkAutoTDelete<GrGLNameAllocator> fPathNameAllocator; + Caps fCaps; MatrixState fHWProjectionMatrixState; GrStencilSettings fHWPathStencilSettings; + struct PathTexGenData { + GrGLenum fMode; + GrGLint fNumComponents; + GrGLfloat fCoefficients[3 * 3]; + }; }; #endif |