diff options
author | Brian Salomon <bsalomon@google.com> | 2017-12-15 11:41:09 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-12-15 17:06:08 +0000 |
commit | 0215e39d7e415d0530231df6ad20d5f215c72152 (patch) | |
tree | 91fec56dae447ceb15e1743117a8ff272c60a7c3 /src | |
parent | 29c14a760682e2c449fa043b5e8b69937cb58f3a (diff) |
Transform vertices for distance field glyphs on CPU.
This allows batching of DF draws with different view matrices.
For perspective matrices this means the transformed position vertex
attribute must have w values. Currently, non-perspective DF draws still
use 2 component positions, though this could be changed in the future.
Consequently, perspective draws can batch with other perspective draws
but not non-perspective draws.
Adds a GM to test batching and reusing the same blobs with both perspective
and non-perspective matrices.
Change-Id: I0e42c5449ebf3a5a54025dbcdec824d904d5bd9e
Reviewed-on: https://skia-review.googlesource.com/79900
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkMatrix.cpp | 24 | ||||
-rw-r--r-- | src/gpu/effects/GrDistanceFieldGeoProc.cpp | 150 | ||||
-rw-r--r-- | src/gpu/effects/GrDistanceFieldGeoProc.h | 66 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLGeometryProcessor.cpp | 33 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLGeometryProcessor.h | 3 | ||||
-rw-r--r-- | src/gpu/ops/GrAtlasTextOp.cpp | 106 | ||||
-rw-r--r-- | src/gpu/ops/GrAtlasTextOp.h | 14 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextBlob.cpp | 79 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextBlob.h | 29 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp | 8 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextContext.cpp | 3 |
11 files changed, 268 insertions, 247 deletions
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp index d02524068e..4851aeacf6 100644 --- a/src/core/SkMatrix.cpp +++ b/src/core/SkMatrix.cpp @@ -1037,32 +1037,48 @@ const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = { /////////////////////////////////////////////////////////////////////////////// -void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const { +void SkMatrix::mapHomogeneousPointsWithStride(SkPoint3 dst[], const SkPoint3 src[], size_t stride, + int count) const { SkASSERT((dst && src && count > 0) || 0 == count); // no partial overlap SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]); if (count > 0) { if (this->isIdentity()) { - memcpy(dst, src, count * sizeof(SkPoint3)); + if (src != dst) { + if (stride == sizeof(SkPoint3)) { + memcpy(dst, src, count * sizeof(SkPoint3)); + } else { + for (int i = 0; i < count; ++i) { + *dst = *src; + dst = reinterpret_cast<SkPoint3*>(reinterpret_cast<char*>(dst) + stride); + src = reinterpret_cast<const SkPoint3*>(reinterpret_cast<const char*>(src) + + stride); + } + } + } return; } do { SkScalar sx = src->fX; SkScalar sy = src->fY; SkScalar sw = src->fZ; - src++; + src = reinterpret_cast<const SkPoint3*>(reinterpret_cast<const char*>(src) + stride); SkScalar x = sdot(sx, fMat[kMScaleX], sy, fMat[kMSkewX], sw, fMat[kMTransX]); SkScalar y = sdot(sx, fMat[kMSkewY], sy, fMat[kMScaleY], sw, fMat[kMTransY]); SkScalar w = sdot(sx, fMat[kMPersp0], sy, fMat[kMPersp1], sw, fMat[kMPersp2]); dst->set(x, y, w); - dst++; + dst = reinterpret_cast<SkPoint3*>(reinterpret_cast<char*>(dst) + stride); } while (--count); } } +void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const { + this->mapHomogeneousPointsWithStride(dst, src, sizeof(SkPoint3), count); +} + /////////////////////////////////////////////////////////////////////////////// void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const { diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp index 2747f55119..b8548bb4db 100644 --- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp +++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp @@ -6,7 +6,6 @@ */ #include "GrDistanceFieldGeoProc.h" - #include "GrAtlasedShaderHelpers.h" #include "GrTexture.h" #include "SkDistanceFieldGen.h" @@ -23,13 +22,7 @@ class GrGLDistanceFieldA8TextGeoProc : public GrGLSLGeometryProcessor { public: - GrGLDistanceFieldA8TextGeoProc() - : fViewMatrix(SkMatrix::InvalidMatrix()) - #ifdef SK_GAMMA_APPLY_TO_A8 - , fDistanceAdjust(-1.0f) - #endif - , fAtlasSize({0,0}) { - } + GrGLDistanceFieldA8TextGeoProc() = default; void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const GrDistanceFieldA8TextGeoProc& dfTexEffect = @@ -61,18 +54,14 @@ public: varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); // Setup position - this->writeOutputPosition(vertBuilder, - uniformHandler, - gpArgs, - dfTexEffect.inPosition()->fName, - dfTexEffect.viewMatrix(), - &fViewMatrixUniform); + gpArgs->fPositionVar = dfTexEffect.inPosition()->asShaderVar(); // emit transforms this->emitTransforms(vertBuilder, varyingHandler, uniformHandler, dfTexEffect.inPosition()->asShaderVar(), + dfTexEffect.localMatrix(), args.fFPCoordTransformHandler); // add varyings @@ -182,13 +171,6 @@ public: } #endif - if (!dfa8gp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfa8gp.viewMatrix())) { - fViewMatrix = dfa8gp.viewMatrix(); - float viewMatrix[3 * 3]; - GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix); - pdman.setMatrix3f(fViewMatrixUniform, viewMatrix); - } - SkASSERT(dfa8gp.numTextureSamplers() >= 1); GrTexture* atlas = dfa8gp.textureSampler(0).peekTexture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); @@ -198,7 +180,7 @@ public: pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height()); } - this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter); + this->setTransformDataHelper(dfa8gp.localMatrix(), pdman, &transformIter); } static inline void GenKey(const GrGeometryProcessor& gp, @@ -206,19 +188,16 @@ public: GrProcessorKeyBuilder* b) { const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldA8TextGeoProc>(); uint32_t key = dfTexEffect.getFlags(); - key |= ComputePosKey(dfTexEffect.viewMatrix()) << 16; b->add32(key); b->add32(dfTexEffect.numTextureSamplers()); } private: - SkMatrix fViewMatrix; - UniformHandle fViewMatrixUniform; #ifdef SK_GAMMA_APPLY_TO_A8 - float fDistanceAdjust; + float fDistanceAdjust = -1.f; UniformHandle fDistanceAdjustUni; #endif - SkISize fAtlasSize; + SkISize fAtlasSize = {0, 0}; UniformHandle fAtlasSizeInvUniform; typedef GrGLSLGeometryProcessor INHERITED; @@ -227,26 +206,28 @@ private: /////////////////////////////////////////////////////////////////////////////// GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc( - GrColor color, - const SkMatrix& viewMatrix, - const sk_sp<GrTextureProxy> proxies[kMaxTextures], - const GrSamplerState& params, + GrColor color, + const sk_sp<GrTextureProxy> proxies[kMaxTextures], + const GrSamplerState& params, #ifdef SK_GAMMA_APPLY_TO_A8 - float distanceAdjust, + float distanceAdjust, #endif - uint32_t flags, - bool usesLocalCoords) + uint32_t flags, + const SkMatrix& localMatrix) : INHERITED(kGrDistanceFieldA8TextGeoProc_ClassID) , fColor(color) - , fViewMatrix(viewMatrix) #ifdef SK_GAMMA_APPLY_TO_A8 , fDistanceAdjust(distanceAdjust) #endif , fFlags(flags & kNonLCD_DistanceFieldEffectMask) , fInColor(nullptr) - , fUsesLocalCoords(usesLocalCoords) { + , fLocalMatrix(localMatrix) { SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask)); - fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType); + if (flags & kPerspective_DistanceFieldEffectFlag) { + fInPosition = &this->addVertexAttrib("inPosition", kFloat3_GrVertexAttribType); + } else { + fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType); + } fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType); fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kUShort2_GrVertexAttribType); for (int i = 0; i < kMaxTextures; ++i) { @@ -303,14 +284,16 @@ sk_sp<GrGeometryProcessor> GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorT if (flags & kSimilarity_DistanceFieldEffectFlag) { flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0; } - - return GrDistanceFieldA8TextGeoProc::Make(GrRandomColor(d->fRandom), - GrTest::TestMatrix(d->fRandom), proxies, + SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom); + GrColor color = GrRandomColor(d->fRandom); + float lum = d->fRandom->nextF(); + return GrDistanceFieldA8TextGeoProc::Make(color, + proxies, samplerState, #ifdef SK_GAMMA_APPLY_TO_A8 - d->fRandom->nextF(), + lum, #endif - flags, d->fRandom->nextBool()); + flags, localMatrix); } #endif @@ -324,7 +307,8 @@ public: } void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ - const GrDistanceFieldPathGeoProc& dfTexEffect = args.fGP.cast<GrDistanceFieldPathGeoProc>(); + const GrDistanceFieldPathGeoProc& dfPathEffect = + args.fGP.cast<GrDistanceFieldPathGeoProc>(); GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; @@ -333,7 +317,7 @@ public: GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes - varyingHandler->emitAttributes(dfTexEffect); + varyingHandler->emitAttributes(dfPathEffect); const char* atlasSizeInvName; fAtlasSizeInvUniform = uniformHandler->addUniform(kVertex_GrShaderFlag, @@ -345,55 +329,55 @@ public: GrGLSLVarying uv(kFloat2_GrSLType); GrGLSLVarying texIdx(kHalf_GrSLType); GrGLSLVarying st(kFloat2_GrSLType); - append_index_uv_varyings(args, dfTexEffect.inTextureCoords()->fName, atlasSizeInvName, - &uv, &texIdx, &st); + append_index_uv_varyings(args, dfPathEffect.inTextureCoords()->fName, atlasSizeInvName, &uv, + &texIdx, &st); // setup pass through color - varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); + varyingHandler->addPassThroughAttribute(dfPathEffect.inColor(), args.fOutputColor); - if (dfTexEffect.matrix().hasPerspective()) { + if (dfPathEffect.matrix().hasPerspective()) { // Setup position this->writeOutputPosition(vertBuilder, uniformHandler, gpArgs, - dfTexEffect.inPosition()->fName, - dfTexEffect.matrix(), + dfPathEffect.inPosition()->fName, + dfPathEffect.matrix(), &fMatrixUniform); // emit transforms this->emitTransforms(vertBuilder, varyingHandler, uniformHandler, - dfTexEffect.inPosition()->asShaderVar(), + dfPathEffect.inPosition()->asShaderVar(), args.fFPCoordTransformHandler); } else { // Setup position - this->writeOutputPosition(vertBuilder, gpArgs, dfTexEffect.inPosition()->fName); + this->writeOutputPosition(vertBuilder, gpArgs, dfPathEffect.inPosition()->fName); // emit transforms this->emitTransforms(vertBuilder, varyingHandler, uniformHandler, - dfTexEffect.inPosition()->asShaderVar(), - dfTexEffect.matrix(), + dfPathEffect.inPosition()->asShaderVar(), + dfPathEffect.matrix(), args.fFPCoordTransformHandler); } // Use highp to work around aliasing issues fragBuilder->codeAppendf("float2 uv = %s;", uv.fsIn()); fragBuilder->codeAppend("half4 texColor;"); - append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(), - texIdx, "uv", "texColor"); + append_multitexture_lookup(args, dfPathEffect.numTextureSamplers(), texIdx, "uv", + "texColor"); fragBuilder->codeAppend("half distance = " SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");"); fragBuilder->codeAppend("half afwidth;"); - bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) == - kUniformScale_DistanceFieldEffectMask; - bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag); + bool isUniformScale = (dfPathEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) == + kUniformScale_DistanceFieldEffectMask; + bool isSimilarity = SkToBool(dfPathEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag); bool isGammaCorrect = - SkToBool(dfTexEffect.getFlags() & kGammaCorrect_DistanceFieldEffectFlag); + SkToBool(dfPathEffect.getFlags() & kGammaCorrect_DistanceFieldEffectFlag); if (isUniformScale) { // For uniform scale, we adjust for the effect of the transformation on the distance // by using the length of the gradient of the t coordinate in the y direction. @@ -589,9 +573,7 @@ sk_sp<GrGeometryProcessor> GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTes class GrGLDistanceFieldLCDTextGeoProc : public GrGLSLGeometryProcessor { public: - GrGLDistanceFieldLCDTextGeoProc() - : fViewMatrix(SkMatrix::InvalidMatrix()) - , fAtlasSize({0,0}) { + GrGLDistanceFieldLCDTextGeoProc() : fAtlasSize({0, 0}) { fDistanceAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(1.0f, 1.0f, 1.0f); } @@ -619,18 +601,14 @@ public: varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); // Setup position - this->writeOutputPosition(vertBuilder, - uniformHandler, - gpArgs, - dfTexEffect.inPosition()->fName, - dfTexEffect.viewMatrix(), - &fViewMatrixUniform); + gpArgs->fPositionVar = dfTexEffect.inPosition()->asShaderVar(); // emit transforms this->emitTransforms(vertBuilder, varyingHandler, uniformHandler, dfTexEffect.inPosition()->asShaderVar(), + dfTexEffect.localMatrix(), args.fFPCoordTransformHandler); // set up varyings @@ -778,13 +756,6 @@ public: fDistanceAdjust = wa; } - if (!dflcd.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dflcd.viewMatrix())) { - fViewMatrix = dflcd.viewMatrix(); - float viewMatrix[3 * 3]; - GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix); - pdman.setMatrix3f(fViewMatrixUniform, viewMatrix); - } - SkASSERT(dflcd.numTextureSamplers() >= 1); GrTexture* atlas = dflcd.textureSampler(0).peekTexture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); @@ -793,8 +764,7 @@ public: fAtlasSize.set(atlas->width(), atlas->height()); pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height()); } - - this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter); + this->setTransformDataHelper(dflcd.localMatrix(), pdman, &transformIter); } static inline void GenKey(const GrGeometryProcessor& gp, @@ -803,15 +773,11 @@ public: const GrDistanceFieldLCDTextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldLCDTextGeoProc>(); uint32_t key = dfTexEffect.getFlags(); - key |= ComputePosKey(dfTexEffect.viewMatrix()) << 16; b->add32(key); b->add32(dfTexEffect.numTextureSamplers()); } private: - SkMatrix fViewMatrix; - UniformHandle fViewMatrixUniform; - GrDistanceFieldLCDTextGeoProc::DistanceAdjust fDistanceAdjust; UniformHandle fDistanceAdjustUni; @@ -824,19 +790,22 @@ private: /////////////////////////////////////////////////////////////////////////////// GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc( GrColor color, - const SkMatrix& viewMatrix, const sk_sp<GrTextureProxy> proxies[kMaxTextures], const GrSamplerState& params, DistanceAdjust distanceAdjust, - uint32_t flags, bool usesLocalCoords) + uint32_t flags, + const SkMatrix& localMatrix) : INHERITED(kGrDistanceFieldLCDTextGeoProc_ClassID) , fColor(color) - , fViewMatrix(viewMatrix) , fDistanceAdjust(distanceAdjust) , fFlags(flags & kLCD_DistanceFieldEffectMask) - , fUsesLocalCoords(usesLocalCoords) { + , fLocalMatrix(localMatrix) { SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag)); - fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType); + if (fFlags & kPerspective_DistanceFieldEffectFlag) { + fInPosition = &this->addVertexAttrib("inPosition", kFloat3_GrVertexAttribType); + } else { + fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType); + } fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType); fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kUShort2_GrVertexAttribType); for (int i = 0; i < kMaxTextures; ++i) { @@ -893,8 +862,9 @@ sk_sp<GrGeometryProcessor> GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessor flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0; } flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0; - return GrDistanceFieldLCDTextGeoProc::Make(GrRandomColor(d->fRandom), - GrTest::TestMatrix(d->fRandom), proxies, - samplerState, wa, flags, d->fRandom->nextBool()); + GrColor color = GrRandomColor(d->fRandom); + SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom); + return GrDistanceFieldLCDTextGeoProc::Make(color, proxies, samplerState, wa, flags, + localMatrix); } #endif diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.h b/src/gpu/effects/GrDistanceFieldGeoProc.h index a09938242f..f3fd67606b 100644 --- a/src/gpu/effects/GrDistanceFieldGeoProc.h +++ b/src/gpu/effects/GrDistanceFieldGeoProc.h @@ -19,24 +19,27 @@ class GrInvariantOutput; enum GrDistanceFieldEffectFlags { kSimilarity_DistanceFieldEffectFlag = 0x01, // ctm is similarity matrix kScaleOnly_DistanceFieldEffectFlag = 0x02, // ctm has only scale and translate - kUseLCD_DistanceFieldEffectFlag = 0x04, // use lcd text - kBGR_DistanceFieldEffectFlag = 0x08, // lcd display has bgr order - kPortrait_DistanceFieldEffectFlag = 0x10, // lcd display is in portrait mode (not used yet) - kGammaCorrect_DistanceFieldEffectFlag = 0x20, // assume gamma-correct output (linear blending) - kAliased_DistanceFieldEffectFlag = 0x40, // monochrome output + kPerspective_DistanceFieldEffectFlag = 0x04, // ctm has perspective (and positions are x,y,w) + kUseLCD_DistanceFieldEffectFlag = 0x08, // use lcd text + kBGR_DistanceFieldEffectFlag = 0x10, // lcd display has bgr order + kPortrait_DistanceFieldEffectFlag = 0x20, // lcd display is in portrait mode (not used yet) + kGammaCorrect_DistanceFieldEffectFlag = 0x40, // assume gamma-correct output (linear blending) + kAliased_DistanceFieldEffectFlag = 0x80, // monochrome output - kInvalid_DistanceFieldEffectFlag = 0x80, // invalid state (for initialization) + kInvalid_DistanceFieldEffectFlag = 0x100, // invalid state (for initialization) kUniformScale_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag | kScaleOnly_DistanceFieldEffectFlag, // The subset of the flags relevant to GrDistanceFieldA8TextGeoProc kNonLCD_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag | kScaleOnly_DistanceFieldEffectFlag | + kPerspective_DistanceFieldEffectFlag | kGammaCorrect_DistanceFieldEffectFlag | kAliased_DistanceFieldEffectFlag, // The subset of the flags relevant to GrDistanceFieldLCDTextGeoProc kLCD_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag | kScaleOnly_DistanceFieldEffectFlag | + kPerspective_DistanceFieldEffectFlag | kUseLCD_DistanceFieldEffectFlag | kBGR_DistanceFieldEffectFlag | kGammaCorrect_DistanceFieldEffectFlag, @@ -52,23 +55,22 @@ class GrDistanceFieldA8TextGeoProc : public GrGeometryProcessor { public: static constexpr int kMaxTextures = 4; + /** The local matrix should be identity if local coords are not required by the GrPipeline. */ #ifdef SK_GAMMA_APPLY_TO_A8 - static sk_sp<GrGeometryProcessor> Make(GrColor color, const SkMatrix& viewMatrix, + static sk_sp<GrGeometryProcessor> Make(GrColor color, const sk_sp<GrTextureProxy> proxies[kMaxTextures], const GrSamplerState& params, float lum, uint32_t flags, - bool usesLocalCoords) { - return sk_sp<GrGeometryProcessor>( - new GrDistanceFieldA8TextGeoProc(color, viewMatrix, proxies, - params, lum, flags, usesLocalCoords)); + const SkMatrix& localMatrixIfUsesLocalCoords) { + return sk_sp<GrGeometryProcessor>(new GrDistanceFieldA8TextGeoProc( + color, proxies, params, lum, flags, localMatrixIfUsesLocalCoords)); } #else - static sk_sp<GrGeometryProcessor> Make(GrColor color, const SkMatrix& viewMatrix, + static sk_sp<GrGeometryProcessor> Make(GrColor color, const sk_sp<GrTextureProxy> proxies[kMaxTextures], const GrSamplerState& params, uint32_t flags, - bool usesLocalCoords) { - return sk_sp<GrGeometryProcessor>( - new GrDistanceFieldA8TextGeoProc(color, viewMatrix, proxies, - params, flags, usesLocalCoords)); + const SkMatrix& localMatrixIfUsesLocalCoords) { + return sk_sp<GrGeometryProcessor>(new GrDistanceFieldA8TextGeoProc( + color, proxies, params, flags, localMatrixIfUsesLocalCoords)); } #endif @@ -80,8 +82,7 @@ public: const Attribute* inColor() const { return fInColor; } const Attribute* inTextureCoords() const { return fInTextureCoords; } GrColor color() const { return fColor; } - const SkMatrix& viewMatrix() const { return fViewMatrix; } - bool usesLocalCoords() const { return fUsesLocalCoords; } + const SkMatrix& localMatrix() const { return fLocalMatrix; } #ifdef SK_GAMMA_APPLY_TO_A8 float getDistanceAdjust() const { return fDistanceAdjust; } #endif @@ -94,16 +95,14 @@ public: GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: - GrDistanceFieldA8TextGeoProc(GrColor, const SkMatrix& viewMatrix, - const sk_sp<GrTextureProxy> proxies[kMaxTextures], + GrDistanceFieldA8TextGeoProc(GrColor, const sk_sp<GrTextureProxy> proxies[kMaxTextures], const GrSamplerState& params, #ifdef SK_GAMMA_APPLY_TO_A8 float distanceAdjust, #endif - uint32_t flags, bool usesLocalCoords); + uint32_t flags, const SkMatrix& localMatrix); GrColor fColor; - SkMatrix fViewMatrix; TextureSampler fTextureSamplers[kMaxTextures]; #ifdef SK_GAMMA_APPLY_TO_A8 float fDistanceAdjust; @@ -112,7 +111,7 @@ private: const Attribute* fInPosition; const Attribute* fInColor; const Attribute* fInTextureCoords; - bool fUsesLocalCoords; + SkMatrix fLocalMatrix; GR_DECLARE_GEOMETRY_PROCESSOR_TEST @@ -129,6 +128,7 @@ class GrDistanceFieldPathGeoProc : public GrGeometryProcessor { public: static constexpr int kMaxTextures = 4; + /** The local matrix should be identity if local coords are not required by the GrPipeline. */ static sk_sp<GrGeometryProcessor> Make(GrColor color, const SkMatrix& matrix, const sk_sp<GrTextureProxy> proxies[kMaxTextures], const GrSamplerState& params, uint32_t flags) { @@ -197,16 +197,13 @@ public: static constexpr int kMaxTextures = 4; static sk_sp<GrGeometryProcessor> Make(GrColor color, - const SkMatrix& viewMatrix, const sk_sp<GrTextureProxy> proxies[kMaxTextures], const GrSamplerState& params, DistanceAdjust distanceAdjust, uint32_t flags, - bool usesLocalCoords) { - return sk_sp<GrGeometryProcessor>( - new GrDistanceFieldLCDTextGeoProc(color, viewMatrix, proxies, - params, distanceAdjust, - flags, usesLocalCoords)); + const SkMatrix& localMatrixIfUsesLocalCoords) { + return sk_sp<GrGeometryProcessor>(new GrDistanceFieldLCDTextGeoProc( + color, proxies, params, distanceAdjust, flags, localMatrixIfUsesLocalCoords)); } ~GrDistanceFieldLCDTextGeoProc() override {} @@ -218,9 +215,8 @@ public: const Attribute* inTextureCoords() const { return fInTextureCoords; } DistanceAdjust getDistanceAdjust() const { return fDistanceAdjust; } GrColor color() const { return fColor; } - const SkMatrix& viewMatrix() const { return fViewMatrix; } uint32_t getFlags() const { return fFlags; } - bool usesLocalCoords() const { return fUsesLocalCoords; } + const SkMatrix& localMatrix() const { return fLocalMatrix; } void addNewProxies(const sk_sp<GrTextureProxy> proxies[kMaxTextures], const GrSamplerState& p); @@ -229,20 +225,18 @@ public: GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: - GrDistanceFieldLCDTextGeoProc(GrColor, const SkMatrix& viewMatrix, - const sk_sp<GrTextureProxy> proxies[kMaxTextures], + GrDistanceFieldLCDTextGeoProc(GrColor, const sk_sp<GrTextureProxy> proxies[kMaxTextures], const GrSamplerState& params, DistanceAdjust wa, uint32_t flags, - bool usesLocalCoords); + const SkMatrix& localMatrix); GrColor fColor; - SkMatrix fViewMatrix; TextureSampler fTextureSamplers[kMaxTextures]; DistanceAdjust fDistanceAdjust; uint32_t fFlags; const Attribute* fInPosition; const Attribute* fInColor; const Attribute* fInTextureCoords; - bool fUsesLocalCoords; + const SkMatrix fLocalMatrix; GR_DECLARE_GEOMETRY_PROCESSOR_TEST diff --git a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp index 9c71042413..9a768c21b4 100644 --- a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp +++ b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp @@ -57,40 +57,43 @@ void GrGLSLGeometryProcessor::emitTransforms(GrGLSLVertexBuilder* vb, const SkMatrix& localMatrix, FPCoordTransformHandler* handler) { SkASSERT(GrSLTypeIsFloatType(localCoordsVar.getType())); - SkASSERT(2 == GrSLTypeVecLength(localCoordsVar.getType())); + SkASSERT(2 == GrSLTypeVecLength(localCoordsVar.getType()) || + 3 == GrSLTypeVecLength(localCoordsVar.getType())); + bool threeComponentLocalCoords = 3 == GrSLTypeVecLength(localCoordsVar.getType()); + SkString localCoords; + if (threeComponentLocalCoords) { + localCoords = localCoordsVar.getName(); + } else { + localCoords.printf("float3(%s, 1)", localCoordsVar.c_str()); + } int i = 0; while (const GrCoordTransform* coordTransform = handler->nextCoordTransform()) { SkString strUniName; strUniName.printf("CoordTransformMatrix_%d", i); - GrSLType varyingType; - - uint32_t type = coordTransform->getMatrix().getType(); - type |= localMatrix.getType(); - - varyingType = SkToBool(SkMatrix::kPerspective_Mask & type) ? kFloat3_GrSLType : - kFloat2_GrSLType; const char* uniName; - - fInstalledTransforms.push_back().fHandle = uniformHandler->addUniform(kVertex_GrShaderFlag, kFloat3x3_GrSLType, strUniName.c_str(), &uniName).toIndex(); + GrSLType varyingType = kFloat2_GrSLType; + if (localMatrix.hasPerspective() || coordTransform->getMatrix().hasPerspective()) { + varyingType = kFloat3_GrSLType; + } SkString strVaryingName; strVaryingName.printf("TransformedCoords_%d", i); - GrGLSLVarying v(varyingType); varyingHandler->addVarying(strVaryingName.c_str(), &v); - SkASSERT(kFloat2_GrSLType == varyingType || kFloat3_GrSLType == varyingType); handler->specifyCoordsForCurrCoordTransform(SkString(v.fsIn()), varyingType); if (kFloat2_GrSLType == varyingType) { - vb->codeAppendf("%s = (%s * float3(%s, 1)).xy;", v.vsOut(), uniName, - localCoordsVar.c_str()); + vb->codeAppendf("%s = (%s * %s).xy;", v.vsOut(), uniName, localCoords.c_str()); + if (threeComponentLocalCoords) { + vb->codeAppendf("%s /= %s.z;", v.vsOut(), localCoords.c_str()); + } } else { - vb->codeAppendf("%s = %s * float3(%s, 1);", v.vsOut(), uniName, localCoordsVar.c_str()); + vb->codeAppendf("%s = %s * %s;", v.vsOut(), uniName, localCoords.c_str()); } ++i; } diff --git a/src/gpu/glsl/GrGLSLGeometryProcessor.h b/src/gpu/glsl/GrGLSLGeometryProcessor.h index de1e4fd02a..36cc546c4c 100644 --- a/src/gpu/glsl/GrGLSLGeometryProcessor.h +++ b/src/gpu/glsl/GrGLSLGeometryProcessor.h @@ -29,7 +29,8 @@ protected: FPCoordTransformIter*); // Emit transformed local coords from the vertex shader as a uniform matrix and varying per - // coord-transform. + // coord-transform. localCoordsVar must be a 2- or 3-component vector. If it is 3 then it is + // assumed to be a 2D homogeneous coordinate. void emitTransforms(GrGLSLVertexBuilder*, GrGLSLVaryingHandler*, GrGLSLUniformHandler*, diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp index 6743feaae6..d71cd92fde 100644 --- a/src/gpu/ops/GrAtlasTextOp.cpp +++ b/src/gpu/ops/GrAtlasTextOp.cpp @@ -6,14 +6,12 @@ */ #include "GrAtlasTextOp.h" - #include "GrContext.h" #include "GrOpFlushState.h" #include "GrResourceProvider.h" - #include "SkGlyphCache.h" #include "SkMathPriv.h" - +#include "SkPoint3.h" #include "effects/GrBitmapTextGeoProc.h" #include "effects/GrDistanceFieldGeoProc.h" #include "text/GrAtlasGlyphCache.h" @@ -22,6 +20,35 @@ static const int kDistanceAdjustLumShift = 5; +void GrAtlasTextOp::init() { + const Geometry& geo = fGeoData[0]; + fColor = geo.fColor; + SkRect bounds; + geo.fBlob->computeSubRunBounds(&bounds, geo.fRun, geo.fSubRun, geo.fViewMatrix, geo.fX, geo.fY); + // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds + // we treat this as a set of non-AA rects rendered with a texture. + this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); + if (this->usesDistanceFields()) { + bool isLCD = this->isLCD(); + + const SkMatrix& viewMatrix = geo.fViewMatrix; + + fDFGPFlags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; + fDFGPFlags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0; + fDFGPFlags |= viewMatrix.hasPerspective() ? kPerspective_DistanceFieldEffectFlag : 0; + fDFGPFlags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0; + fDFGPFlags |= (kAliasedDistanceField_MaskType == fMaskType) + ? kAliased_DistanceFieldEffectFlag + : 0; + + if (isLCD) { + fDFGPFlags |= kUseLCD_DistanceFieldEffectFlag; + fDFGPFlags |= + (kLCDBGRDistanceField_MaskType == fMaskType) ? kBGR_DistanceFieldEffectFlag : 0; + } + } +} + SkString GrAtlasTextOp::dumpInfo() const { SkString str; @@ -183,7 +210,7 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix. // TODO actually only invert if we don't have RGBA SkMatrix localMatrix; - if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) { + if (this->usesLocalCoords() && !fGeoData[0].fViewMatrix.invert(&localMatrix)) { SkDebugf("Cannot invert viewmatrix\n"); return; } @@ -200,8 +227,10 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { FlushInfo flushInfo; flushInfo.fPipeline = target->makePipeline(fSRGBFlags, std::move(fProcessors), target->detachAppliedClip()); + SkDEBUGCODE(bool dfPerspective = false); if (this->usesDistanceFields()) { flushInfo.fGeometryProcessor = this->setupDfProcessor(); + SkDEBUGCODE(dfPerspective = fGeoData[0].fViewMatrix.hasPerspective()); } else { flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make( this->color(), proxies, GrSamplerState::ClampNearest(), maskFormat, @@ -210,7 +239,7 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { flushInfo.fGlyphsToFlush = 0; size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride(); - SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat)); + SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat, dfPerspective)); int glyphCount = this->numGlyphs(); const GrBuffer* vertexBuffer; @@ -242,9 +271,24 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { if (args.fClipRect.isEmpty()) { memcpy(currVertex, result.fFirstVertex, vertexBytes); } else { + SkASSERT(!dfPerspective); clip_quads(args.fClipRect, currVertex, result.fFirstVertex, vertexStride, result.fGlyphsRegenerated); } + if (this->usesDistanceFields() && !args.fViewMatrix.isIdentity()) { + // We always do the distance field view matrix transformation after copying rather + // than during blob vertex generation time in the blob as handling successive + // arbitrary transformations would be complicated and accumulate error. + if (args.fViewMatrix.hasPerspective()) { + auto* pos = reinterpret_cast<SkPoint3*>(currVertex); + args.fViewMatrix.mapHomogeneousPointsWithStride( + pos, pos, vertexStride, result.fGlyphsRegenerated * kVerticesPerGlyph); + } else { + auto* pos = reinterpret_cast<SkPoint*>(currVertex); + args.fViewMatrix.mapPointsWithStride( + pos, vertexStride, result.fGlyphsRegenerated * kVerticesPerGlyph); + } + } flushInfo.fGlyphsToFlush += result.fGlyphsRegenerated; if (!result.fFinished) { this->flush(target, &flushInfo); @@ -300,19 +344,23 @@ bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { return false; } - if (!this->usesDistanceFields()) { - if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) { + const SkMatrix& thisFirstMatrix = fGeoData[0].fViewMatrix; + const SkMatrix& thatFirstMatrix = that->fGeoData[0].fViewMatrix; + + if (this->usesLocalCoords() && !thisFirstMatrix.cheapEqualTo(thatFirstMatrix)) { + return false; + } + + if (this->usesDistanceFields()) { + if (fDFGPFlags != that->fDFGPFlags) { return false; } - if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { + + if (fLuminanceColor != that->fLuminanceColor) { return false; } } else { - if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { - return false; - } - - if (fLuminanceColor != that->fLuminanceColor) { + if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) { return false; } } @@ -358,20 +406,18 @@ bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { // TODO trying to figure out why lcd is so whack // (see comments in GrAtlasTextContext::ComputeCanonicalColor) sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor() const { - const SkMatrix& viewMatrix = this->viewMatrix(); const sk_sp<GrTextureProxy>* p = fFontCache->getProxies(this->maskFormat()); bool isLCD = this->isLCD(); - // set up any flags - uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; - flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0; - flags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0; - flags |= (kAliasedDistanceField_MaskType == fMaskType) ? kAliased_DistanceFieldEffectFlag : 0; + + SkMatrix localMatrix = SkMatrix::I(); + if (this->usesLocalCoords()) { + // If this fails we'll just use I(). + bool result = fGeoData[0].fViewMatrix.invert(&localMatrix); + (void)result; + } // see if we need to create a new effect if (isLCD) { - flags |= kUseLCD_DistanceFieldEffectFlag; - flags |= (kLCDBGRDistanceField_MaskType == fMaskType) ? kBGR_DistanceFieldEffectFlag : 0; - float redCorrection = fDistanceAdjustTable->getAdjustment( SkColorGetR(fLuminanceColor) >> kDistanceAdjustLumShift, fUseGammaCorrectDistanceTable); @@ -384,10 +430,8 @@ sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor() const { GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make( redCorrection, greenCorrection, blueCorrection); - - return GrDistanceFieldLCDTextGeoProc::Make(this->color(), viewMatrix, p, - GrSamplerState::ClampBilerp(), widthAdjust, - flags, this->usesLocalCoords()); + return GrDistanceFieldLCDTextGeoProc::Make(this->color(), p, GrSamplerState::ClampBilerp(), + widthAdjust, fDFGPFlags, localMatrix); } else { #ifdef SK_GAMMA_APPLY_TO_A8 float correction = 0; @@ -397,13 +441,11 @@ sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor() const { correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift, fUseGammaCorrectDistanceTable); } - return GrDistanceFieldA8TextGeoProc::Make(this->color(), viewMatrix, p, - GrSamplerState::ClampBilerp(), correction, flags, - this->usesLocalCoords()); + return GrDistanceFieldA8TextGeoProc::Make(this->color(), p, GrSamplerState::ClampBilerp(), + correction, fDFGPFlags, localMatrix); #else - return GrDistanceFieldA8TextGeoProc::Make(this->color(), viewMatrix, p, - GrSamplerState::ClampBilerp(), flags, - this->usesLocalCoords()); + return GrDistanceFieldA8TextGeoProc::Make(this->color(), p, GrSamplerState::ClampBilerp(), + fDFGPFlags, localMatrix); #endif } } diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h index d31a3297ec..cb15c36fb8 100644 --- a/src/gpu/ops/GrAtlasTextOp.h +++ b/src/gpu/ops/GrAtlasTextOp.h @@ -87,16 +87,8 @@ public: // init() so the op can initialize itself Geometry& geometry() { return fGeoData[0]; } - void init() { - const Geometry& geo = fGeoData[0]; - fColor = geo.fColor; - SkRect bounds; - geo.fBlob->computeSubRunBounds(&bounds, geo.fRun, geo.fSubRun, geo.fViewMatrix, geo.fX, - geo.fY); - // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds - // we treat this as a set of non-AA rects rendered with a texture. - this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); - } + /** Called after this->geometry() has been configured. */ + void init(); const char* name() const override { return "AtlasTextOp"; } @@ -187,7 +179,6 @@ private: inline void flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const; GrColor color() const { return fColor; } - const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } bool usesLocalCoords() const { return fUsesLocalCoords; } int numGlyphs() const { return fNumGlyphs; } @@ -212,6 +203,7 @@ private: sk_sp<const GrDistanceFieldAdjustTable> fDistanceAdjustTable; SkColor fLuminanceColor; bool fUseGammaCorrectDistanceTable; + uint32_t fDFGPFlags = 0; typedef GrMeshDrawOp INHERITED; }; diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp index 0b25a34ed1..02f3ab0a21 100644 --- a/src/gpu/text/GrAtlasTextBlob.cpp +++ b/src/gpu/text/GrAtlasTextBlob.cpp @@ -96,7 +96,13 @@ void GrAtlasTextBlob::appendGlyph(int runIndex, run.fInitialized = true; - size_t vertexStride = GetVertexStride(format); + bool hasW = subRun->hasWCoord(); + // DF glyphs drawn in perspective must always have a w coord. + SkASSERT(hasW || !subRun->drawAsDistanceFields() || !fInitialViewMatrix.hasPerspective()); + // Non-DF glyphs should never have a w coord. + SkASSERT(!hasW || subRun->drawAsDistanceFields()); + + size_t vertexStride = GetVertexStride(format, hasW); subRun->setMaskFormat(format); @@ -105,53 +111,29 @@ void GrAtlasTextBlob::appendGlyph(int runIndex, intptr_t vertex = reinterpret_cast<intptr_t>(this->fVertices + subRun->vertexEndIndex()); - if (kARGB_GrMaskFormat != glyph->fMaskFormat) { - // V0 - SkPoint* position = reinterpret_cast<SkPoint*>(vertex); - position->set(positions.fLeft, positions.fTop); - SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); - *colorPtr = color; - vertex += vertexStride; - - // V1 - position = reinterpret_cast<SkPoint*>(vertex); - position->set(positions.fLeft, positions.fBottom); - colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); - *colorPtr = color; - vertex += vertexStride; - - // V2 - position = reinterpret_cast<SkPoint*>(vertex); - position->set(positions.fRight, positions.fTop); - colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); - *colorPtr = color; - vertex += vertexStride; - - // V3 - position = reinterpret_cast<SkPoint*>(vertex); - position->set(positions.fRight, positions.fBottom); - colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); - *colorPtr = color; - } else { - // V0 - SkPoint* position = reinterpret_cast<SkPoint*>(vertex); - position->set(positions.fLeft, positions.fTop); - vertex += vertexStride; - - // V1 - position = reinterpret_cast<SkPoint*>(vertex); - position->set(positions.fLeft, positions.fBottom); - vertex += vertexStride; - - // V2 - position = reinterpret_cast<SkPoint*>(vertex); - position->set(positions.fRight, positions.fTop); - vertex += vertexStride; - - // V3 - position = reinterpret_cast<SkPoint*>(vertex); - position->set(positions.fRight, positions.fBottom); - } + // We always write the third position component used by SDFs. If it is unused it gets + // overwritten. Similarly, we always write the color and the blob will later overwrite it + // with texture coords if it is unused. + size_t colorOffset = hasW ? sizeof(SkPoint3) : sizeof(SkPoint); + // V0 + *reinterpret_cast<SkPoint3*>(vertex) = {positions.fLeft, positions.fTop, 1.f}; + *reinterpret_cast<GrColor*>(vertex + colorOffset) = color; + vertex += vertexStride; + + // V1 + *reinterpret_cast<SkPoint3*>(vertex) = {positions.fLeft, positions.fBottom, 1.f}; + *reinterpret_cast<GrColor*>(vertex + colorOffset) = color; + vertex += vertexStride; + + // V2 + *reinterpret_cast<SkPoint3*>(vertex) = {positions.fRight, positions.fTop, 1.f}; + *reinterpret_cast<GrColor*>(vertex + colorOffset) = color; + vertex += vertexStride; + + // V3 + *reinterpret_cast<SkPoint3*>(vertex) = {positions.fRight, positions.fBottom, 1.f}; + *reinterpret_cast<GrColor*>(vertex + colorOffset) = color; + subRun->appendVertices(vertexStride); fGlyphs[subRun->glyphEndIndex()] = glyph; subRun->glyphAppended(); @@ -185,6 +167,7 @@ bool GrAtlasTextBlob::mustRegenerate(const GrTextUtils::Paint& paint, return true; } + /** This could be relaxed for blobs with only distance field glyphs. */ if (fInitialViewMatrix.hasPerspective() && !fInitialViewMatrix.cheapEqualTo(viewMatrix)) { return true; } diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h index 450e256d38..282fa98141 100644 --- a/src/gpu/text/GrAtlasTextBlob.h +++ b/src/gpu/text/GrAtlasTextBlob.h @@ -17,6 +17,7 @@ #include "SkMaskFilter.h" #include "SkOpts.h" #include "SkPathEffect.h" +#include "SkPoint3.h" #include "SkRasterizer.h" #include "SkSurfaceProps.h" #include "SkTInternalLList.h" @@ -53,6 +54,12 @@ public: static sk_sp<GrAtlasTextBlob> Make(GrMemoryPool* pool, int glyphCount, int runCount); + /** + * We currently force regeneration of a blob if old or new matrix differ in having perspective. + * If we ever change that then the key must contain the perspectiveness when there are distance + * fields as perspective distance field use 3 component vertex positions and non-perspective + * uses 2. + */ struct Key { Key() { sk_bzero(this, sizeof(Key)); @@ -126,12 +133,13 @@ public: } // sets the last subrun of runIndex to use distance field text - void setSubRunHasDistanceFields(int runIndex, bool hasLCD, bool isAntiAlias) { + void setSubRunHasDistanceFields(int runIndex, bool hasLCD, bool isAntiAlias, bool hasWCoord) { Run& run = fRuns[runIndex]; Run::SubRunInfo& subRun = run.fSubRunInfo.back(); subRun.setUseLCDText(hasLCD); subRun.setAntiAliased(isAntiAlias); subRun.setDrawAsDistanceFields(); + subRun.setHasWCoord(hasWCoord); } void setRunDrawAsPaths(int runIndex) { @@ -169,13 +177,15 @@ public: SkGlyphCache*, const SkGlyph& skGlyph, SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP); - static size_t GetVertexStride(GrMaskFormat maskFormat) { + static size_t GetVertexStride(GrMaskFormat maskFormat, bool isDistanceFieldWithWCoord) { switch (maskFormat) { case kA8_GrMaskFormat: - return kGrayTextVASize; + return isDistanceFieldWithWCoord ? kGrayTextDFPerspectiveVASize : kGrayTextVASize; case kARGB_GrMaskFormat: + SkASSERT(!isDistanceFieldWithWCoord); return kColorTextVASize; default: + SkASSERT(!isDistanceFieldWithWCoord); return kLCDTextVASize; } } @@ -232,8 +242,10 @@ public: // position + local coord static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16); + static const size_t kGrayTextDFPerspectiveVASize = + sizeof(SkPoint3) + sizeof(GrColor) + sizeof(SkIPoint16); static const size_t kLCDTextVASize = kGrayTextVASize; - static const size_t kMaxVASize = kGrayTextVASize; + static const size_t kMaxVASize = kGrayTextDFPerspectiveVASize; static const int kVerticesPerGlyph = 4; static void AssertEqual(const GrAtlasTextBlob&, const GrAtlasTextBlob&); @@ -419,7 +431,7 @@ private: // This function assumes the translation will be applied before it is called again void computeTranslation(const SkMatrix& viewMatrix, SkScalar x, SkScalar y, - SkScalar*transX, SkScalar* transY); + SkScalar* transX, SkScalar* transY); // df properties void setDrawAsDistanceFields() { fFlags |= kDrawAsSDF_Flag; } @@ -432,12 +444,17 @@ private: fFlags = antiAliased ? fFlags | kAntiAliased_Flag : fFlags & ~kAntiAliased_Flag; } bool isAntiAliased() const { return SkToBool(fFlags & kAntiAliased_Flag); } + void setHasWCoord(bool hasW) { + fFlags = hasW ? (fFlags | kHasWCoord_Flag) : fFlags & ~kHasWCoord_Flag; + } + bool hasWCoord() const { return SkToBool(fFlags & kHasWCoord_Flag); } private: enum Flag { kDrawAsSDF_Flag = 0x1, kUseLCDText_Flag = 0x2, - kAntiAliased_Flag = 0x4 + kAntiAliased_Flag = 0x4, + kHasWCoord_Flag = 0x8 }; GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken; diff --git a/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp index 28b2e0f0c0..1be5ae330c 100644 --- a/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp +++ b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp @@ -71,8 +71,8 @@ inline void regen_vertices(char* vertex, const GrGlyph* glyph, size_t vertexStri // This is a bit wonky, but sometimes we have LCD text, in which case we won't have color // vertices, hence vertexStride - sizeof(SkIPoint16) - intptr_t colorOffset = sizeof(SkPoint); intptr_t texCoordOffset = vertexStride - sizeof(SkIPoint16); + intptr_t colorOffset = texCoordOffset - sizeof(GrColor); // V0 if (regenPos) { @@ -211,8 +211,9 @@ Regenerator::Result Regenerator::doRegen() { } } + bool hasW = fSubRun->hasWCoord(); Result result; - auto vertexStride = GetVertexStride(fSubRun->maskFormat()); + auto vertexStride = GetVertexStride(fSubRun->maskFormat(), hasW); char* currVertex = fBlob->fVertices + fSubRun->vertexStartIndex() + fCurrGlyph * kVerticesPerGlyph * vertexStride; result.fFirstVertex = currVertex; @@ -300,7 +301,8 @@ Regenerator::Result Regenerator::regenerate() { return this->doRegen<false, true, true, true>(); case kNoRegen: { Result result; - auto vertexStride = GetVertexStride(fSubRun->maskFormat()); + bool hasW = fSubRun->hasWCoord(); + auto vertexStride = GetVertexStride(fSubRun->maskFormat(), hasW); result.fGlyphsRegenerated = fSubRun->glyphCount() - fCurrGlyph; result.fFirstVertex = fBlob->fVertices + fSubRun->vertexStartIndex() + fCurrGlyph * kVerticesPerGlyph * vertexStride; diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp index d617786944..3faa0f7b87 100644 --- a/src/gpu/text/GrAtlasTextContext.cpp +++ b/src/gpu/text/GrAtlasTextContext.cpp @@ -646,13 +646,14 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, SkTDArray<char> fallbackTxt; SkTDArray<SkScalar> fallbackPos; + bool hasWCoord = viewMatrix.hasPerspective(); // Setup distance field paint and text ratio SkScalar textRatio; SkPaint dfPaint(paint); this->initDistanceFieldPaint(blob, &dfPaint, &textRatio, viewMatrix); blob->setHasDistanceField(); blob->setSubRunHasDistanceFields(runIndex, paint.skPaint().isLCDRenderText(), - paint.skPaint().isAntiAlias()); + paint.skPaint().isAntiAlias(), hasWCoord); GrAtlasTextStrike* currStrike = nullptr; |