diff options
-rw-r--r-- | gyp/gpu.gypi | 1 | ||||
-rw-r--r-- | src/gpu/GrDrawTarget.h | 31 | ||||
-rw-r--r-- | src/gpu/GrGpu.cpp | 11 | ||||
-rw-r--r-- | src/gpu/GrGpu.h | 17 | ||||
-rw-r--r-- | src/gpu/GrInOrderDrawBuffer.cpp | 2 | ||||
-rw-r--r-- | src/gpu/GrPathRendering.h | 75 | ||||
-rw-r--r-- | src/gpu/GrStencilAndCoverTextContext.cpp | 12 | ||||
-rw-r--r-- | src/gpu/gl/GrGLPath.cpp | 6 | ||||
-rw-r--r-- | src/gpu/gl/GrGLPathRange.cpp | 6 | ||||
-rw-r--r-- | src/gpu/gl/GrGLPathRendering.cpp | 336 | ||||
-rw-r--r-- | src/gpu/gl/GrGLPathRendering.h | 64 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 4 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgramEffects.cpp | 14 | ||||
-rw-r--r-- | src/gpu/gl/GrGLUtil.cpp | 25 | ||||
-rw-r--r-- | src/gpu/gl/GrGLUtil.h | 4 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGL.cpp | 344 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGL.h | 42 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGL_program.cpp | 4 |
18 files changed, 531 insertions, 467 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index 589cc51b1d..ec2a07fc97 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -97,6 +97,7 @@ '<(skia_src_path)/gpu/GrPathRendererChain.cpp', '<(skia_src_path)/gpu/GrPathRenderer.cpp', '<(skia_src_path)/gpu/GrPathRenderer.h', + '<(skia_src_path)/gpu/GrPathRendering.h', '<(skia_src_path)/gpu/GrPathUtils.cpp', '<(skia_src_path)/gpu/GrPathUtils.h', '<(skia_src_path)/gpu/GrPictureUtils.h', diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h index d1023d2682..998f41282d 100644 --- a/src/gpu/GrDrawTarget.h +++ b/src/gpu/GrDrawTarget.h @@ -12,6 +12,7 @@ #include "GrContext.h" #include "GrDrawState.h" #include "GrIndexBuffer.h" +#include "GrPathRendering.h" #include "GrTraceMarker.h" #include "SkClipStack.h" @@ -36,6 +37,9 @@ protected: public: SK_DECLARE_INST_COUNT(GrDrawTarget) + + typedef GrPathRendering::PathTransformType PathTransformType ; + /////////////////////////////////////////////////////////////////////////// // The context may not be fully constructed and should not be used during GrDrawTarget @@ -333,38 +337,11 @@ public: PathTransformSize(transformsType) * count elements * @param fill Fill type for drawing all the paths */ - enum PathTransformType { - kNone_PathTransformType, //!< [] - kTranslateX_PathTransformType, //!< [kMTransX] - kTranslateY_PathTransformType, //!< [kMTransY] - kTranslate_PathTransformType, //!< [kMTransX, kMTransY] - kAffine_PathTransformType, //!< [kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY] - - kLast_PathTransformType = kAffine_PathTransformType - }; void drawPaths(const GrPathRange* pathRange, const uint32_t indices[], int count, const float transforms[], PathTransformType transformsType, SkPath::FillType fill); - static inline int PathTransformSize(PathTransformType type) { - switch (type) { - case kNone_PathTransformType: - return 0; - case kTranslateX_PathTransformType: - case kTranslateY_PathTransformType: - return 1; - case kTranslate_PathTransformType: - return 2; - case kAffine_PathTransformType: - return 6; - - default: - SkFAIL("Unknown path transform type"); - return 0; - } - } - /** * Helper function for drawing rects. It performs a geometry src push and pop * and thus will finalize any reserved geometry. diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index 0b49e7445a..74df26002d 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -215,13 +215,12 @@ GrIndexBuffer* GrGpu::createIndexBuffer(size_t size, bool dynamic) { GrPath* GrGpu::createPath(const SkPath& path, const SkStrokeRec& stroke) { SkASSERT(this->caps()->pathRenderingSupport()); this->handleDirtyContext(); - return this->onCreatePath(path, stroke); + return this->pathRendering()->createPath(path, stroke); } GrPathRange* GrGpu::createPathRange(size_t size, const SkStrokeRec& stroke) { - SkASSERT(this->caps()->pathRenderingSupport()); this->handleDirtyContext(); - return this->onCreatePathRange(size, stroke); + return this->pathRendering()->createPathRange(size, stroke); } void GrGpu::clear(const SkIRect* rect, @@ -407,7 +406,7 @@ void GrGpu::onStencilPath(const GrPath* path, SkPath::FillType fill) { return; } - this->onGpuStencilPath(path, fill); + this->pathRendering()->stencilPath(path, fill); } @@ -422,7 +421,7 @@ void GrGpu::onDrawPath(const GrPath* path, SkPath::FillType fill, return; } - this->onGpuDrawPath(path, fill); + this->pathRendering()->drawPath(path, fill); } void GrGpu::onDrawPaths(const GrPathRange* pathRange, @@ -438,7 +437,7 @@ void GrGpu::onDrawPaths(const GrPathRange* pathRange, return; } - this->onGpuDrawPaths(pathRange, indices, count, transforms, transformsType, fill); + this->pathRendering()->drawPaths(pathRange, indices, count, transforms, transformsType, fill); } void GrGpu::finalizeReservedVertices() { diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index b752f7c09c..5020bddb39 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -10,6 +10,7 @@ #include "GrDrawTarget.h" #include "GrClipMaskManager.h" +#include "GrPathRendering.h" #include "SkPath.h" class GrContext; @@ -54,6 +55,10 @@ public: GrContext* getContext() { return this->INHERITED::getContext(); } const GrContext* getContext() const { return this->INHERITED::getContext(); } + GrPathRendering* pathRendering() { + return fPathRendering.get(); + } + /** * The GrGpu object normally assumes that no outsider is setting state * within the underlying 3D API's context/device/whatever. This call informs @@ -410,6 +415,8 @@ protected: void finalizeReservedVertices(); void finalizeReservedIndices(); + SkAutoTDelete<GrPathRendering> fPathRendering; + private: // GrDrawTarget overrides virtual bool onReserveVertexSpace(size_t vertexSize, int vertexCount, void** vertices) SK_OVERRIDE; @@ -438,8 +445,6 @@ private: virtual GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) = 0; virtual GrVertexBuffer* onCreateVertexBuffer(size_t size, bool dynamic) = 0; virtual GrIndexBuffer* onCreateIndexBuffer(size_t size, bool dynamic) = 0; - virtual GrPath* onCreatePath(const SkPath& path, const SkStrokeRec&) = 0; - virtual GrPathRange* onCreatePathRange(size_t size, const SkStrokeRec&) = 0; // overridden by backend-specific derived class to perform the clear and // clearRect. NULL rect means clear whole target. If canIgnoreRect is @@ -449,14 +454,6 @@ private: // overridden by backend-specific derived class to perform the draw call. virtual void onGpuDraw(const DrawInfo&) = 0; - // overridden by backend-specific derived class to perform the path stenciling. - virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) = 0; - virtual void onGpuDrawPath(const GrPath*, SkPath::FillType) = 0; - virtual void onGpuDrawPaths(const GrPathRange*, - const uint32_t indices[], int count, - const float transforms[], PathTransformType, - SkPath::FillType) = 0; - // overridden by backend-specific derived class to perform the read pixels. virtual bool onReadPixels(GrRenderTarget* target, int left, int top, int width, int height, diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp index 6d0bbd11c0..9df54a8076 100644 --- a/src/gpu/GrInOrderDrawBuffer.cpp +++ b/src/gpu/GrInOrderDrawBuffer.cpp @@ -430,7 +430,7 @@ void GrInOrderDrawBuffer::onDrawPaths(const GrPathRange* pathRange, memcpy(dp->fIndices, indices, sizeof(uint32_t) * count); dp->fCount = count; - const int transformsLength = PathTransformSize(transformsType) * count; + const int transformsLength = GrPathRendering::PathTransformSize(transformsType) * count; dp->fTransforms = SkNEW_ARRAY(float, transformsLength); memcpy(dp->fTransforms, transforms, sizeof(float) * transformsLength); dp->fTransformsType = transformsType; diff --git a/src/gpu/GrPathRendering.h b/src/gpu/GrPathRendering.h new file mode 100644 index 0000000000..863da270c7 --- /dev/null +++ b/src/gpu/GrPathRendering.h @@ -0,0 +1,75 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrPathRendering_DEFINED +#define GrPathRendering_DEFINED + +#include "SkPath.h" + +class SkStrokeRec; +class GrPath; +class GrPathRange; +class GrGpu; + +/** + * Abstract class wrapping HW path rendering API. + * + * The subclasses of this class use the possible HW API to render paths (as opposed to path + * rendering implemented in Skia on top of a "3d" HW API). + * The subclasses hold the global state needed to render paths, including shadow of the global HW + * API state. Similar to GrGpu. + * + * It is expected that the lifetimes of GrGpuXX and GrXXPathRendering are the same. The call context + * interface (eg. * the concrete instance of GrGpu subclass) should be provided to the instance + * during construction. + */ +class GrPathRendering { +public: + virtual ~GrPathRendering() { } + + enum PathTransformType { + kNone_PathTransformType, //!< [] + kTranslateX_PathTransformType, //!< [kMTransX] + kTranslateY_PathTransformType, //!< [kMTransY] + kTranslate_PathTransformType, //!< [kMTransX, kMTransY] + kAffine_PathTransformType, //!< [kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY] + + kLast_PathTransformType = kAffine_PathTransformType + }; + + static inline int PathTransformSize(PathTransformType type) { + switch (type) { + case kNone_PathTransformType: + return 0; + case kTranslateX_PathTransformType: + case kTranslateY_PathTransformType: + return 1; + case kTranslate_PathTransformType: + return 2; + case kAffine_PathTransformType: + return 6; + + default: + SkFAIL("Unknown path transform type"); + return 0; + } + } + + virtual GrPath* createPath(const SkPath&, const SkStrokeRec&) = 0; + virtual GrPathRange* createPathRange(size_t size, const SkStrokeRec&) = 0; + virtual void stencilPath(const GrPath*, SkPath::FillType) = 0; + virtual void drawPath(const GrPath*, SkPath::FillType) = 0; + virtual void drawPaths(const GrPathRange*, const uint32_t indices[], int count, + const float transforms[], PathTransformType, SkPath::FillType) = 0; +protected: + GrPathRendering() { } + +private: + GrPathRendering& operator=(const GrPathRendering&); +}; + +#endif diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp index ff7c23ef23..af4ba64343 100644 --- a/src/gpu/GrStencilAndCoverTextContext.cpp +++ b/src/gpu/GrStencilAndCoverTextContext.cpp @@ -155,7 +155,7 @@ void GrStencilAndCoverTextContext::drawText(const GrPaint& paint, SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, glyphCacheTransform); fGlyphCache = autoCache.getCache(); fGlyphs = GlyphPathRange::Create(fContext, fGlyphCache, fStroke); - fTransformType = GrDrawTarget::kTranslate_PathTransformType; + fTransformType = GrPathRendering::kTranslate_PathTransformType; const char* stop = text + byteLength; @@ -243,7 +243,7 @@ void GrStencilAndCoverTextContext::drawPosText(const GrPaint& paint, if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { if (1 == scalarsPerPosition) { - fTransformType = GrDrawTarget::kTranslateX_PathTransformType; + fTransformType = GrPathRendering::kTranslateX_PathTransformType; while (text < stop) { const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); if (glyph.fWidth) { @@ -253,7 +253,7 @@ void GrStencilAndCoverTextContext::drawPosText(const GrPaint& paint, } } else { SkASSERT(2 == scalarsPerPosition); - fTransformType = GrDrawTarget::kTranslate_PathTransformType; + fTransformType = GrPathRendering::kTranslate_PathTransformType; while (text < stop) { const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); if (glyph.fWidth) { @@ -263,7 +263,7 @@ void GrStencilAndCoverTextContext::drawPosText(const GrPaint& paint, } } } else { - fTransformType = GrDrawTarget::kTranslate_PathTransformType; + fTransformType = GrPathRendering::kTranslate_PathTransformType; SkTextMapStateProc tmsProc(SkMatrix::I(), 0, scalarsPerPosition); SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); while (text < stop) { @@ -396,7 +396,7 @@ void GrStencilAndCoverTextContext::init(const GrPaint& paint, } inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x) { - SkASSERT(GrDrawTarget::kTranslateX_PathTransformType == fTransformType); + SkASSERT(GrPathRendering::kTranslateX_PathTransformType == fTransformType); if (fPendingGlyphCount >= kGlyphBufferSize) { this->flush(); @@ -411,7 +411,7 @@ inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x) } inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x, float y) { - SkASSERT(GrDrawTarget::kTranslate_PathTransformType == fTransformType); + SkASSERT(GrPathRendering::kTranslate_PathTransformType == fTransformType); if (fPendingGlyphCount >= kGlyphBufferSize) { this->flush(); diff --git a/src/gpu/gl/GrGLPath.cpp b/src/gpu/gl/GrGLPath.cpp index 6f158cdea9..930ec4a8f6 100644 --- a/src/gpu/gl/GrGLPath.cpp +++ b/src/gpu/gl/GrGLPath.cpp @@ -85,7 +85,7 @@ void GrGLPath::InitPathObject(GrGpuGL* gpu, GrGLuint pathID, const SkPath& skPath, const SkStrokeRec& stroke) { - GrGLPathRendering* pr = gpu->pathRendering(); + GrGLPathRendering* pr = gpu->glPathRendering(); SkSTArray<16, GrGLubyte, true> pathCommands; SkSTArray<16, SkPoint, true> pathPoints; @@ -121,7 +121,7 @@ void GrGLPath::InitPathObject(GrGpuGL* gpu, GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path, const SkStrokeRec& stroke) : INHERITED(gpu, kIsWrapped, path, stroke), - fPathID(gpu->pathRendering()->genPaths(1)) { + fPathID(gpu->glPathRendering()->genPaths(1)) { SkASSERT(!path.isEmpty()); InitPathObject(gpu, fPathID, fSkPath, stroke); @@ -138,7 +138,7 @@ GrGLPath::~GrGLPath() { void GrGLPath::onRelease() { if (0 != fPathID && !this->isWrapped()) { - static_cast<GrGpuGL*>(this->getGpu())->pathRendering()->deletePaths(fPathID, 1); + static_cast<GrGpuGL*>(this->getGpu())->glPathRendering()->deletePaths(fPathID, 1); fPathID = 0; } diff --git a/src/gpu/gl/GrGLPathRange.cpp b/src/gpu/gl/GrGLPathRange.cpp index 5e89cb5d87..9aaf9db26b 100644 --- a/src/gpu/gl/GrGLPathRange.cpp +++ b/src/gpu/gl/GrGLPathRange.cpp @@ -13,7 +13,7 @@ GrGLPathRange::GrGLPathRange(GrGpuGL* gpu, size_t size, const SkStrokeRec& stroke) : INHERITED(gpu, size, stroke), - fBasePathID(gpu->pathRendering()->genPaths(fSize)), + fBasePathID(gpu->glPathRendering()->genPaths(fSize)), fNumDefinedPaths(0) { } @@ -28,7 +28,7 @@ void GrGLPathRange::initAt(size_t index, const SkPath& skPath) { } // Make sure the path at this index hasn't been initted already. - SkASSERT(GR_GL_FALSE == gpu->pathRendering()->isPath(fBasePathID + index)); + SkASSERT(GR_GL_FALSE == gpu->glPathRendering()->isPath(fBasePathID + index)); GrGLPath::InitPathObject(gpu, fBasePathID + index, skPath, fStroke); ++fNumDefinedPaths; @@ -39,7 +39,7 @@ void GrGLPathRange::onRelease() { SkASSERT(NULL != this->getGpu()); if (0 != fBasePathID && !this->isWrapped()) { - static_cast<GrGpuGL*>(this->getGpu())->pathRendering()->deletePaths(fBasePathID, fSize); + static_cast<GrGpuGL*>(this->getGpu())->glPathRendering()->deletePaths(fBasePathID, fSize); fBasePathID = 0; } diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp index 249d98139a..53d7cf0074 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)); } diff --git a/src/gpu/gl/GrGLPathRendering.h b/src/gpu/gl/GrGLPathRendering.h index 53b8750356..e16f0591a7 100644 --- a/src/gpu/gl/GrGLPathRendering.h +++ b/src/gpu/gl/GrGLPathRendering.h @@ -9,28 +9,40 @@ #define GrGLPathRendering_DEFINED #include "SkRefCnt.h" +#include "GrPathRendering.h" +#include "GrStencil.h" #include "gl/GrGLFunctions.h" +#include "gl/GrGLProgram.h" class GrGLNameAllocator; -struct GrGLInterface; +class GrGpuGL; /** * This class wraps the NV_path_rendering extension and manages its various - * API versions. If a method is not present in the GrGLInterface (because the - * driver version is old), it tries to provide a backup implementation. But if - * a backup implementation is not practical, it marks the method as not - * supported. + * API versions. If a method is not present in the GrGLInterface of the GrGpuGL + * (because the driver version is old), it tries to provide a backup + * implementation. But if a backup implementation is not practical, it marks the + * method as not supported. */ -class GrGLPathRendering { +class GrGLPathRendering : public GrPathRendering { public: /** - * Create a new GrGLPathRendering object from a given GL interface. Unless + * Create a new GrGLPathRendering object from a given GrGpuGL. Unless * otherwise specified in the caps, every method will work properly, even - * if it did not exist in the GL interface. + * if it did not exist in the GL interface of the gpu. */ - static GrGLPathRendering* Create(const GrGLInterface*); + static GrGLPathRendering* Create(GrGpuGL* gpu); virtual ~GrGLPathRendering(); + // GrPathRendering implementations. + virtual GrPath* createPath(const SkPath&, const SkStrokeRec&) SK_OVERRIDE; + virtual GrPathRange* createPathRange(size_t size, const SkStrokeRec&) SK_OVERRIDE; + virtual void stencilPath(const GrPath*, SkPath::FillType) SK_OVERRIDE; + virtual void drawPath(const GrPath*, SkPath::FillType) SK_OVERRIDE; + virtual void drawPaths(const GrPathRange*, const uint32_t indices[], int count, + const float transforms[], PathTransformType, + SkPath::FillType) SK_OVERRIDE; + /** * Mark certain functionality as not supported if the driver version is too * old and a backup implementation is not practical. @@ -40,12 +52,29 @@ public: }; const Caps& caps() const { return fCaps; } + + /* Called when the 3D context state is unknown. */ + void resetContext(); + /** * Called when the GPU resources have been lost and need to be abandoned * (for example after a context loss). */ void abandonGpuResources(); + enum PathTexGenComponents { + kS_PathTexGenComponents = 1, + kST_PathTexGenComponents = 2, + kSTR_PathTexGenComponents = 3 + }; + void enablePathTexGen(int unitIdx, PathTexGenComponents, const GrGLfloat* coefficients); + void enablePathTexGen(int unitIdx, PathTexGenComponents, const SkMatrix& matrix); + void flushPathTexGenSettings(int numUsedTexCoordSets); + void setProjectionMatrix(const SkMatrix& matrix, + const SkISize& renderTargetSize, + GrSurfaceOrigin renderTargetOrigin); + + // NV_path_rendering GrGLuint genPaths(GrGLsizei range); GrGLvoid deletePaths(GrGLuint path, GrGLsizei range); @@ -98,11 +127,24 @@ public: const GrGLfloat *coeffs); protected: - GrGLPathRendering(const GrGLInterface*); + GrGLPathRendering(GrGpuGL* gpu); - SkAutoTUnref<const GrGLInterface> fGLInterface; + GrGpuGL* fGpu; SkAutoTDelete<GrGLNameAllocator> fPathNameAllocator; Caps fCaps; + GrGLProgram::MatrixState fHWProjectionMatrixState; + GrStencilSettings fHWPathStencilSettings; + struct PathTexGenData { + GrGLenum fMode; + GrGLint fNumComponents; + GrGLfloat fCoefficients[3 * 3]; + }; + int fHWActivePathTexGenSets; + SkTArray<PathTexGenData, true> fHWPathTexGenSettings; + +private: + void flushPathStencilSettings(SkPath::FillType fill); + }; #endif diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index 0ad7a18756..d8c751d71d 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -154,7 +154,7 @@ void GrGLProgram::setData(GrDrawState::BlendOptFlags blendOpts, // custom shaders, it's ignored, so we don't need to change the texgen // settings in that case. if (!fHasVertexShader) { - fGpu->flushPathTexGenSettings(fTexCoordSetCnt); + fGpu->glPathRendering()->flushPathTexGenSettings(fTexCoordSetCnt); } } @@ -247,7 +247,7 @@ void GrGLProgram::setMatrixAndRenderTargetHeight(const GrDrawState& drawState) { if (!fHasVertexShader) { SkASSERT(!fBuiltinUniformHandles.fViewMatrixUni.isValid()); SkASSERT(!fBuiltinUniformHandles.fRTAdjustmentUni.isValid()); - fGpu->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin()); + fGpu->glPathRendering()->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin()); } else if (fMatrixState.fRenderTargetOrigin != rt->origin() || fMatrixState.fRenderTargetSize != size || !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix())) { diff --git a/src/gpu/gl/GrGLProgramEffects.cpp b/src/gpu/gl/GrGLProgramEffects.cpp index 3fa4f15ac8..8ea77d05eb 100644 --- a/src/gpu/gl/GrGLProgramEffects.cpp +++ b/src/gpu/gl/GrGLProgramEffects.cpp @@ -478,16 +478,18 @@ void GrGLPathTexGenProgramEffects::setPathTexGenState(GrGpuGL* gpu, switch (get_matrix_type(totalKey, t)) { case kNoPersp_MatrixType: { const SkMatrix& transform = get_transform_matrix(drawEffect, t); - gpu->enablePathTexGen(texCoordIndex++, - GrGpuGL::kST_PathTexGenComponents, - transform); + gpu->glPathRendering()->enablePathTexGen( + texCoordIndex++, + GrGLPathRendering::kST_PathTexGenComponents, + transform); break; } case kGeneral_MatrixType: { const SkMatrix& transform = get_transform_matrix(drawEffect, t); - gpu->enablePathTexGen(texCoordIndex++, - GrGpuGL::kSTR_PathTexGenComponents, - transform); + gpu->glPathRendering()->enablePathTexGen( + texCoordIndex++, + GrGLPathRendering::kSTR_PathTexGenComponents, + transform); break; } default: diff --git a/src/gpu/gl/GrGLUtil.cpp b/src/gpu/gl/GrGLUtil.cpp index 86a3a59e91..9bc2c5d67a 100644 --- a/src/gpu/gl/GrGLUtil.cpp +++ b/src/gpu/gl/GrGLUtil.cpp @@ -264,3 +264,28 @@ template<> void GrGLGetMatrix<4>(GrGLfloat* dest, const SkMatrix& src) { dest[14] = 0; dest[15] = SkScalarToFloat(src[SkMatrix::kMPersp2]); } + +GrGLenum GrToGLStencilFunc(GrStencilFunc basicFunc) { + static const GrGLenum gTable[] = { + GR_GL_ALWAYS, // kAlways_StencilFunc + GR_GL_NEVER, // kNever_StencilFunc + GR_GL_GREATER, // kGreater_StencilFunc + GR_GL_GEQUAL, // kGEqual_StencilFunc + GR_GL_LESS, // kLess_StencilFunc + GR_GL_LEQUAL, // kLEqual_StencilFunc, + GR_GL_EQUAL, // kEqual_StencilFunc, + GR_GL_NOTEQUAL, // kNotEqual_StencilFunc, + }; + GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kBasicStencilFuncCount); + GR_STATIC_ASSERT(0 == kAlways_StencilFunc); + GR_STATIC_ASSERT(1 == kNever_StencilFunc); + GR_STATIC_ASSERT(2 == kGreater_StencilFunc); + GR_STATIC_ASSERT(3 == kGEqual_StencilFunc); + GR_STATIC_ASSERT(4 == kLess_StencilFunc); + GR_STATIC_ASSERT(5 == kLEqual_StencilFunc); + GR_STATIC_ASSERT(6 == kEqual_StencilFunc); + GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc); + SkASSERT((unsigned) basicFunc < kBasicStencilFuncCount); + + return gTable[basicFunc]; +} diff --git a/src/gpu/gl/GrGLUtil.h b/src/gpu/gl/GrGLUtil.h index 89d8076139..06210ee1ab 100644 --- a/src/gpu/gl/GrGLUtil.h +++ b/src/gpu/gl/GrGLUtil.h @@ -10,6 +10,7 @@ #include "gl/GrGLInterface.h" #include "GrGLDefines.h" +#include "GrStencil.h" class SkMatrix; @@ -181,4 +182,7 @@ template<int MatrixSize> void GrGLGetMatrix(GrGLfloat* dest, const SkMatrix& src // call glGetError without doing a redundant error check or logging. #define GR_GL_GET_ERROR(IFACE) (IFACE)->fFunctions.fGetError() +GrGLenum GrToGLStencilFunc(GrStencilFunc basicFunc); + + #endif diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp index 7131cfa1eb..c6bd6bbe14 100644 --- a/src/gpu/gl/GrGpuGL.cpp +++ b/src/gpu/gl/GrGpuGL.cpp @@ -8,9 +8,6 @@ #include "GrGpuGL.h" #include "GrGLStencilBuffer.h" -#include "GrGLPath.h" -#include "GrGLPathRange.h" -#include "GrGLPathRendering.h" #include "GrGLShaderBuilder.h" #include "GrTemplates.h" #include "GrTypes.h" @@ -35,20 +32,6 @@ /////////////////////////////////////////////////////////////////////////////// -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 == GrDrawTarget::kNone_PathTransformType); -GR_STATIC_ASSERT(1 == GrDrawTarget::kTranslateX_PathTransformType); -GR_STATIC_ASSERT(2 == GrDrawTarget::kTranslateY_PathTransformType); -GR_STATIC_ASSERT(3 == GrDrawTarget::kTranslate_PathTransformType); -GR_STATIC_ASSERT(4 == GrDrawTarget::kAffine_PathTransformType); -GR_STATIC_ASSERT(GrDrawTarget::kAffine_PathTransformType == GrDrawTarget::kLast_PathTransformType); static const GrGLenum gXfermodeCoeff2Blend[] = { GR_GL_ZERO, @@ -137,7 +120,6 @@ GrGpuGL::GrGpuGL(const GrGLContext& ctx, GrContext* context) fCaps.reset(SkRef(ctx.caps())); fHWBoundTextureUniqueIDs.reset(this->glCaps().maxFragmentTextureUnits()); - fHWPathTexGenSettings.reset(this->glCaps().maxFixedFunctionTextureCoords()); GrGLClearErr(fGLContext.interface()); if (gPrintStartupSpew) { @@ -166,7 +148,7 @@ GrGpuGL::GrGpuGL(const GrGLContext& ctx, GrContext* context) fHWProgramID = 0; if (this->glCaps().pathRenderingSupport()) { - fPathRendering.reset(GrGLPathRendering::Create(glInterface())); + fPathRendering.reset(GrGLPathRendering::Create(this)); } } @@ -328,18 +310,8 @@ void GrGpuGL::onResetContext(uint32_t resetBits) { if (resetBits & kPathRendering_GrGLBackendState) { if (this->caps()->pathRenderingSupport()) { - fHWProjectionMatrixState.invalidate(); - // we don't use the model view matrix. - GL_CALL(MatrixLoadIdentity(GR_GL_MODELVIEW)); - - for (int i = 0; i < this->glCaps().maxFixedFunctionTextureCoords(); ++i) { - fPathRendering->pathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL); - fHWPathTexGenSettings[i].fMode = GR_GL_NONE; - fHWPathTexGenSettings[i].fNumComponents = 0; - } - fHWActivePathTexGenSets = 0; + this->glPathRendering()->resetContext(); } - fHWPathStencilSettings.invalidate(); } // we assume these values @@ -1372,16 +1344,6 @@ GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(size_t size, bool dynamic) { } } -GrPath* GrGpuGL::onCreatePath(const SkPath& inPath, const SkStrokeRec& stroke) { - SkASSERT(this->caps()->pathRenderingSupport()); - return SkNEW_ARGS(GrGLPath, (this, inPath, stroke)); -} - -GrPathRange* GrGpuGL::onCreatePathRange(size_t size, const SkStrokeRec& stroke) { - SkASSERT(this->caps()->pathRenderingSupport()); - return SkNEW_ARGS(GrGLPathRange, (this, size, stroke)); -} - void GrGpuGL::flushScissor() { if (fScissorState.fEnabled) { // Only access the RT if scissoring is being enabled. We can call this before performing @@ -1839,168 +1801,6 @@ void GrGpuGL::onGpuDraw(const DrawInfo& info) { #endif } -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; - } -} - -void GrGpuGL::onGpuStencilPath(const GrPath* path, SkPath::FillType fill) { - SkASSERT(this->caps()->pathRenderingSupport()); - - GrGLuint id = static_cast<const GrGLPath*>(path)->pathID(); - SkASSERT(NULL != this->drawState()->getRenderTarget()); - SkASSERT(NULL != this->drawState()->getRenderTarget()->getStencilBuffer()); - - flushPathStencilSettings(fill); - - // Decide how to manipulate the stencil buffer based on the fill rule. - 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); - fPathRendering->stencilFillPath(id, fillMode, writeMask); -} - -void GrGpuGL::onGpuDrawPath(const GrPath* path, SkPath::FillType fill) { - SkASSERT(this->caps()->pathRenderingSupport()); - - GrGLuint id = static_cast<const GrGLPath*>(path)->pathID(); - SkASSERT(NULL != this->drawState()->getRenderTarget()); - SkASSERT(NULL != this->drawState()->getRenderTarget()->getStencilBuffer()); - SkASSERT(!fCurrentProgram->hasVertexShader()); - - 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()) { - fPathRendering->stencilFillPath(id, fillMode, writeMask); - } - fPathRendering->stencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX); - } else { - fPathRendering->stencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX); - } - } else { - if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) { - fPathRendering->stencilFillPath(id, fillMode, writeMask); - } - if (stroke.needToApply()) { - fPathRendering->stencilStrokePath(id, 0xffff, writeMask); - } - - GrDrawState* drawState = this->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); - } - - this->drawSimpleRect(bounds); - } -} - -void GrGpuGL::onGpuDrawPaths(const GrPathRange* pathRange, - const uint32_t indices[], int count, - const float transforms[], PathTransformType transformsType, - SkPath::FillType fill) { - SkASSERT(this->caps()->pathRenderingSupport()); - SkASSERT(NULL != this->drawState()->getRenderTarget()); - SkASSERT(NULL != this->drawState()->getRenderTarget()->getStencilBuffer()); - SkASSERT(!fCurrentProgram->hasVertexShader()); - - GrGLuint baseID = static_cast<const GrGLPathRange*>(pathRange)->basePathID(); - - 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()) { - fPathRendering->stencilFillPathInstanced( - count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode, - writeMask, gXformType2GLType[transformsType], - transforms); - } - fPathRendering->stencilThenCoverStrokePathInstanced( - count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff, writeMask, - GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES, - gXformType2GLType[transformsType], transforms); - } else { - fPathRendering->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()) { - fPathRendering->stencilFillPathInstanced( - count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode, - writeMask, gXformType2GLType[transformsType], - transforms); - } - if (stroke.needToApply()) { - fPathRendering->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, - 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); - } - - this->drawSimpleRect(bounds); - } -} - void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) { GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target); if (rt->needsResolve()) { @@ -2046,30 +1846,6 @@ void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) { namespace { -GrGLenum gr_to_gl_stencil_func(GrStencilFunc basicFunc) { - static const GrGLenum gTable[] = { - GR_GL_ALWAYS, // kAlways_StencilFunc - GR_GL_NEVER, // kNever_StencilFunc - GR_GL_GREATER, // kGreater_StencilFunc - GR_GL_GEQUAL, // kGEqual_StencilFunc - GR_GL_LESS, // kLess_StencilFunc - GR_GL_LEQUAL, // kLEqual_StencilFunc, - GR_GL_EQUAL, // kEqual_StencilFunc, - GR_GL_NOTEQUAL, // kNotEqual_StencilFunc, - }; - GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kBasicStencilFuncCount); - GR_STATIC_ASSERT(0 == kAlways_StencilFunc); - GR_STATIC_ASSERT(1 == kNever_StencilFunc); - GR_STATIC_ASSERT(2 == kGreater_StencilFunc); - GR_STATIC_ASSERT(3 == kGEqual_StencilFunc); - GR_STATIC_ASSERT(4 == kLess_StencilFunc); - GR_STATIC_ASSERT(5 == kLEqual_StencilFunc); - GR_STATIC_ASSERT(6 == kEqual_StencilFunc); - GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc); - SkASSERT((unsigned) basicFunc < kBasicStencilFuncCount); - - return gTable[basicFunc]; -} GrGLenum gr_to_gl_stencil_op(GrStencilOp op) { static const GrGLenum gTable[] = { @@ -2099,7 +1875,7 @@ void set_gl_stencil(const GrGLInterface* gl, const GrStencilSettings& settings, GrGLenum glFace, GrStencilSettings::Face grFace) { - GrGLenum glFunc = gr_to_gl_stencil_func(settings.func(grFace)); + GrGLenum glFunc = GrToGLStencilFunc(settings.func(grFace)); GrGLenum glFailOp = gr_to_gl_stencil_op(settings.failOp(grFace)); GrGLenum glPassOp = gr_to_gl_stencil_op(settings.passOp(grFace)); @@ -2187,22 +1963,6 @@ void GrGpuGL::flushAAState(DrawType type) { } } -void GrGpuGL::flushPathStencilSettings(SkPath::FillType fill) { - GrStencilSettings pathStencilSettings; - this->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 = - gr_to_gl_stencil_func(pathStencilSettings.func(GrStencilSettings::kFront_Face)); - fPathRendering->pathStencilFunc( - func, pathStencilSettings.funcRef(GrStencilSettings::kFront_Face), - pathStencilSettings.funcMask(GrStencilSettings::kFront_Face)); - - fHWPathStencilSettings = pathStencilSettings; - } -} - void GrGpuGL::flushBlend(bool isLines, GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) { @@ -2349,104 +2109,6 @@ void GrGpuGL::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTextur texture->setCachedTexParams(newTexParams, this->getResetTimestamp()); } -void GrGpuGL::setProjectionMatrix(const SkMatrix& matrix, - const SkISize& renderTargetSize, - GrSurfaceOrigin renderTargetOrigin) { - - SkASSERT(this->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)); -} - -void GrGpuGL::enablePathTexGen(int unitIdx, - PathTexGenComponents components, - const GrGLfloat* coefficients) { - SkASSERT(this->glCaps().pathRenderingSupport()); - SkASSERT(components >= kS_PathTexGenComponents && - components <= kSTR_PathTexGenComponents); - SkASSERT(this->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; - } - - this->setTextureUnit(unitIdx); - - fHWPathTexGenSettings[unitIdx].fNumComponents = components; - fPathRendering->pathTexGen(GR_GL_TEXTURE0 + unitIdx, - GR_GL_OBJECT_LINEAR, - components, - coefficients); - - memcpy(fHWPathTexGenSettings[unitIdx].fCoefficients, coefficients, - 3 * components * sizeof(GrGLfloat)); -} - -void GrGpuGL::enablePathTexGen(int unitIdx, PathTexGenComponents components, - const SkMatrix& matrix) { - GrGLfloat coefficients[3 * 3]; - SkASSERT(this->glCaps().pathRenderingSupport()); - 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]); - } - - enablePathTexGen(unitIdx, components, coefficients); -} - -void GrGpuGL::flushPathTexGenSettings(int numUsedTexCoordSets) { - SkASSERT(this->glCaps().pathRenderingSupport()); - SkASSERT(this->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); - - this->setTextureUnit(i); - fPathRendering->pathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL); - fHWPathTexGenSettings[i].fNumComponents = 0; - } - - fHWActivePathTexGenSets = numUsedTexCoordSets; -} - void GrGpuGL::flushMiscFixedFunctionState() { const GrDrawState& drawState = this->getDrawState(); diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h index b39aedb824..40104f8825 100644 --- a/src/gpu/gl/GrGpuGL.h +++ b/src/gpu/gl/GrGpuGL.h @@ -12,6 +12,7 @@ #include "GrGLContext.h" #include "GrGLIRect.h" #include "GrGLIndexBuffer.h" +#include "GrGLPathRendering.h" #include "GrGLProgram.h" #include "GrGLStencilBuffer.h" #include "GrGLTexture.h" @@ -24,8 +25,6 @@ #define PROGRAM_CACHE_STATS #endif -class GrGLPathRendering; - class GrGpuGL : public GrGpu { public: GrGpuGL(const GrGLContext& ctx, GrContext* context); @@ -40,9 +39,9 @@ public: GrGLSLGeneration glslGeneration() const { return fGLContext.glslGeneration(); } const GrGLCaps& glCaps() const { return *fGLContext.caps(); } - GrGLPathRendering* pathRendering() const { + GrGLPathRendering* glPathRendering() { SkASSERT(glCaps().pathRenderingSupport()); - return fPathRendering.get(); + return static_cast<GrGLPathRendering*>(pathRendering()); } virtual void discard(GrRenderTarget*) SK_OVERRIDE; @@ -50,17 +49,7 @@ public: // Used by GrGLProgram and GrGLPathTexGenProgramEffects to configure OpenGL // state. void bindTexture(int unitIdx, const GrTextureParams& params, GrGLTexture* texture); - void setProjectionMatrix(const SkMatrix& matrix, - const SkISize& renderTargetSize, - GrSurfaceOrigin renderTargetOrigin); - enum PathTexGenComponents { - kS_PathTexGenComponents = 1, - kST_PathTexGenComponents = 2, - kSTR_PathTexGenComponents = 3 - }; - void enablePathTexGen(int unitIdx, PathTexGenComponents, const GrGLfloat* coefficients); - void enablePathTexGen(int unitIdx, PathTexGenComponents, const SkMatrix& matrix); - void flushPathTexGenSettings(int numUsedTexCoordSets); + bool shouldUseFixedFunctionTexturing() const { return this->glCaps().pathRenderingSupport(); } @@ -131,8 +120,6 @@ private: const void* srcData) SK_OVERRIDE; virtual GrVertexBuffer* onCreateVertexBuffer(size_t size, bool dynamic) SK_OVERRIDE; virtual GrIndexBuffer* onCreateIndexBuffer(size_t size, bool dynamic) SK_OVERRIDE; - virtual GrPath* onCreatePath(const SkPath&, const SkStrokeRec&) SK_OVERRIDE; - virtual GrPathRange* onCreatePathRange(size_t size, const SkStrokeRec&) SK_OVERRIDE; virtual GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&) SK_OVERRIDE; virtual GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) SK_OVERRIDE; virtual bool createStencilBufferForRenderTarget(GrRenderTarget* rt, @@ -160,12 +147,6 @@ private: virtual void onGpuDraw(const DrawInfo&) SK_OVERRIDE; - virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) SK_OVERRIDE; - virtual void onGpuDrawPath(const GrPath*, SkPath::FillType) SK_OVERRIDE; - virtual void onGpuDrawPaths(const GrPathRange*, - const uint32_t indices[], int count, - const float transforms[], PathTransformType, - SkPath::FillType) SK_OVERRIDE; virtual void clearStencil() SK_OVERRIDE; virtual void clearStencilClip(const SkIRect& rect, @@ -257,7 +238,6 @@ private: void flushRenderTarget(const SkIRect* bound); void flushStencil(DrawType); void flushAAState(DrawType); - void flushPathStencilSettings(SkPath::FillType fill); bool configToGLFormats(GrPixelConfig config, bool getSizedInternal, @@ -445,11 +425,9 @@ private: TriState fMSAAEnabled; - GrGLProgram::MatrixState fHWProjectionMatrixState; - GrStencilSettings fHWStencilSettings; TriState fHWStencilTestEnabled; - GrStencilSettings fHWPathStencilSettings; + GrDrawState::DrawFace fHWDrawFace; TriState fHWWriteToColor; @@ -457,22 +435,14 @@ private: uint32_t fHWBoundRenderTargetUniqueID; SkTArray<uint32_t, true> fHWBoundTextureUniqueIDs; - struct PathTexGenData { - GrGLenum fMode; - GrGLint fNumComponents; - GrGLfloat fCoefficients[3 * 3]; - }; - int fHWActivePathTexGenSets; - SkTArray<PathTexGenData, true> fHWPathTexGenSettings; ///@} // we record what stencil format worked last time to hopefully exit early // from our loop that tries stencil formats and calls check fb status. int fLastSuccessfulStencilFmtIdx; - SkAutoTDelete<GrGLPathRendering> fPathRendering; - typedef GrGpu INHERITED; + friend class GrGLPathRendering; // For accessing setTextureUnit. }; #endif diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp index beaaa903b2..c4011e7314 100644 --- a/src/gpu/gl/GrGpuGL_program.cpp +++ b/src/gpu/gl/GrGpuGL_program.cpp @@ -204,7 +204,7 @@ void GrGpuGL::abandonResources(){ fProgramCache->abandon(); fHWProgramID = 0; if (this->glCaps().pathRenderingSupport()) { - fPathRendering->abandonGpuResources(); + this->glPathRendering()->abandonGpuResources(); } } @@ -222,7 +222,7 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC const GrRenderTarget* rt = this->getDrawState().getRenderTarget(); SkISize size; size.set(rt->width(), rt->height()); - this->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin()); + this->glPathRendering()->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin()); } else { this->flushMiscFixedFunctionState(); |