diff options
author | Jim Van Verth <jvanverth@google.com> | 2017-10-19 15:50:24 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-10-20 12:28:05 +0000 |
commit | 58c3cce1144f83bc7e4ee5e93931b8721560735b (patch) | |
tree | 99815dd93f58c6a14ea9952b176e5a04a6b26653 /src | |
parent | e576d14e5d484116eb261f54c6306e98b6e19b2e (diff) |
Clip text geometrically when possible.
Currently when we clip text we can't batch the clipped text with non-clipped text.
By modifying the quads and texCoords we can produce the same effect, and allow batching.
Includes some minor text code cleanup.
Bug: skia:6990
Change-Id: Ibfd4bc2fdc2d7680071e2abddd4d77fc3017e3d3
Reviewed-on: https://skia-review.googlesource.com/60780
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/ops/GrAtlasTextOp.cpp | 139 | ||||
-rw-r--r-- | src/gpu/ops/GrAtlasTextOp.h | 15 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextBlob.cpp | 41 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextBlob.h | 13 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextBlob_regenInOp.cpp | 4 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextContext.cpp | 3 | ||||
-rw-r--r-- | src/gpu/text/GrTextUtils.cpp | 1 |
7 files changed, 173 insertions, 43 deletions
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp index 1c67fe7db9..fb041e0268 100644 --- a/src/gpu/ops/GrAtlasTextOp.cpp +++ b/src/gpu/ops/GrAtlasTextOp.cpp @@ -76,6 +76,108 @@ GrDrawOp::RequiresDstTexture GrAtlasTextOp::finalize(const GrCaps& caps, return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo; } +static void clip_quads(const SkIRect& clipRect, + unsigned char* currVertex, unsigned char* blobVertices, + size_t vertexStride, int glyphCount) { + for (int i = 0; i < glyphCount; ++i) { + SkPoint* blobPositionLT = reinterpret_cast<SkPoint*>(blobVertices); + SkPoint* blobPositionRB = reinterpret_cast<SkPoint*>(blobVertices + 3*vertexStride); + + SkRect positionRect = SkRect::MakeLTRB(blobPositionLT->fX, + blobPositionLT->fY, + blobPositionRB->fX, + blobPositionRB->fY); + if (clipRect.contains(positionRect)) { + memcpy(currVertex, blobVertices, 4 * vertexStride); + currVertex += 4 * vertexStride; + } else { + // Pull out some more data that we'll need. + // In the LCD case the color will be garbage, but we'll overwrite it with the texcoords + // and it avoids a lot of conditionals. + SkColor color = *reinterpret_cast<SkColor*>(blobVertices + sizeof(SkPoint)); + size_t coordOffset = vertexStride - sizeof(SkIPoint16); + SkIPoint16* blobCoordsLT = reinterpret_cast<SkIPoint16*>(blobVertices + coordOffset); + SkIPoint16* blobCoordsRB = reinterpret_cast<SkIPoint16*>(blobVertices + + 3*vertexStride + + coordOffset); + SkIRect coordsRect = SkIRect::MakeLTRB(blobCoordsLT->fX >> 1, + blobCoordsLT->fY >> 1, + blobCoordsRB->fX >> 1, + blobCoordsRB->fY >> 1); + int pageIndexX = blobCoordsLT->fX & 0x1; + int pageIndexY = blobCoordsLT->fY & 0x1; + + SkASSERT(positionRect.width() == coordsRect.width()); + + // Clip position and texCoords to the clipRect + if (positionRect.fLeft < clipRect.fLeft) { + coordsRect.fLeft += clipRect.fLeft - positionRect.fLeft; + positionRect.fLeft = clipRect.fLeft; + } + if (positionRect.fTop < clipRect.fTop) { + coordsRect.fTop += clipRect.fTop - positionRect.fTop; + positionRect.fTop = clipRect.fTop; + } + if (positionRect.fRight > clipRect.fRight) { + coordsRect.fRight += clipRect.fRight - positionRect.fRight; + positionRect.fRight = clipRect.fRight; + } + if (positionRect.fBottom > clipRect.fBottom) { + coordsRect.fBottom += clipRect.fBottom - positionRect.fBottom; + positionRect.fBottom = clipRect.fBottom; + } + if (positionRect.fLeft > positionRect.fRight) { + positionRect.fLeft = positionRect.fRight; + } + if (positionRect.fTop > positionRect.fBottom) { + positionRect.fTop = positionRect.fBottom; + } + coordsRect.fLeft = coordsRect.fLeft << 1 | pageIndexX; + coordsRect.fTop = coordsRect.fTop << 1 | pageIndexY; + coordsRect.fRight = coordsRect.fRight << 1 | pageIndexX; + coordsRect.fBottom = coordsRect.fBottom << 1 | pageIndexY; + + SkPoint* currPosition = reinterpret_cast<SkPoint*>(currVertex); + currPosition->fX = positionRect.fLeft; + currPosition->fY = positionRect.fTop; + *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color; + SkIPoint16* currCoords = reinterpret_cast<SkIPoint16*>(currVertex + coordOffset); + currCoords->fX = coordsRect.fLeft; + currCoords->fY = coordsRect.fTop; + currVertex += vertexStride; + + currPosition = reinterpret_cast<SkPoint*>(currVertex); + currPosition->fX = positionRect.fLeft; + currPosition->fY = positionRect.fBottom; + *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color; + currCoords = reinterpret_cast<SkIPoint16*>(currVertex + coordOffset); + currCoords->fX = coordsRect.fLeft; + currCoords->fY = coordsRect.fBottom; + currVertex += vertexStride; + + currPosition = reinterpret_cast<SkPoint*>(currVertex); + currPosition->fX = positionRect.fRight; + currPosition->fY = positionRect.fTop; + *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color; + currCoords = reinterpret_cast<SkIPoint16*>(currVertex + coordOffset); + currCoords->fX = coordsRect.fRight; + currCoords->fY = coordsRect.fTop; + currVertex += vertexStride; + + currPosition = reinterpret_cast<SkPoint*>(currVertex); + currPosition->fX = positionRect.fRight; + currPosition->fY = positionRect.fBottom; + *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color; + currCoords = reinterpret_cast<SkIPoint16*>(currVertex + coordOffset); + currCoords->fX = coordsRect.fRight; + currCoords->fY = coordsRect.fBottom; + currVertex += vertexStride; + } + + blobVertices += 4 * vertexStride; + } +} + 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 @@ -98,9 +200,7 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { flushInfo.fPipeline = target->makePipeline(fSRGBFlags, std::move(fProcessors), target->detachAppliedClip()); if (this->usesDistanceFields()) { - flushInfo.fGeometryProcessor = - this->setupDfProcessor(this->viewMatrix(), - fLuminanceColor, this->color(), proxies); + flushInfo.fGeometryProcessor = this->setupDfProcessor(); } else { flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make( this->color(), proxies, GrSamplerState::ClampNearest(), maskFormat, @@ -127,6 +227,7 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { GrBlobRegenHelper helper(this, target, &flushInfo); SkAutoGlyphCache glyphCache; + // each of these is a SubRun for (int i = 0; i < fGeoCount; i++) { const Geometry& args = fGeoData[i]; Blob* blob = args.fBlob; @@ -138,7 +239,12 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { &blobVertices, &byteCount, &subRunGlyphCount); // now copy all vertices - memcpy(currVertex, blobVertices, byteCount); + if (args.fClipRect.isEmpty()) { + memcpy(currVertex, blobVertices, byteCount); + } else { + clip_quads(args.fClipRect, currVertex, reinterpret_cast<unsigned char*>(blobVertices), + vertexStride, subRunGlyphCount); + } currVertex += byteCount; } @@ -237,13 +343,11 @@ bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { return true; } -// TODO just use class params // TODO trying to figure out why lcd is so whack -sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor( - const SkMatrix& viewMatrix, - SkColor luminanceColor, - GrColor color, - const sk_sp<GrTextureProxy> p[kMaxTextures]) const { +// (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; @@ -257,34 +361,35 @@ sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor( flags |= (kLCDBGRDistanceField_MaskType == fMaskType) ? kBGR_DistanceFieldEffectFlag : 0; float redCorrection = fDistanceAdjustTable->getAdjustment( - SkColorGetR(luminanceColor) >> kDistanceAdjustLumShift, + SkColorGetR(fLuminanceColor) >> kDistanceAdjustLumShift, fUseGammaCorrectDistanceTable); float greenCorrection = fDistanceAdjustTable->getAdjustment( - SkColorGetG(luminanceColor) >> kDistanceAdjustLumShift, + SkColorGetG(fLuminanceColor) >> kDistanceAdjustLumShift, fUseGammaCorrectDistanceTable); float blueCorrection = fDistanceAdjustTable->getAdjustment( - SkColorGetB(luminanceColor) >> kDistanceAdjustLumShift, + SkColorGetB(fLuminanceColor) >> kDistanceAdjustLumShift, fUseGammaCorrectDistanceTable); GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make( redCorrection, greenCorrection, blueCorrection); - return GrDistanceFieldLCDTextGeoProc::Make(color, viewMatrix, p, + return GrDistanceFieldLCDTextGeoProc::Make(this->color(), viewMatrix, p, GrSamplerState::ClampBilerp(), widthAdjust, flags, this->usesLocalCoords()); } else { #ifdef SK_GAMMA_APPLY_TO_A8 float correction = 0; if (kAliasedDistanceField_MaskType != fMaskType) { - U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, luminanceColor); + U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, + fLuminanceColor); correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift, fUseGammaCorrectDistanceTable); } - return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, p, + return GrDistanceFieldA8TextGeoProc::Make(this->color(), viewMatrix, p, GrSamplerState::ClampBilerp(), correction, flags, this->usesLocalCoords()); #else - return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, p, + return GrDistanceFieldA8TextGeoProc::Make(this->color(), viewMatrix, p, GrSamplerState::ClampBilerp(), flags, this->usesLocalCoords()); #endif diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h index 0738ce7f20..07627367cc 100644 --- a/src/gpu/ops/GrAtlasTextOp.h +++ b/src/gpu/ops/GrAtlasTextOp.h @@ -28,12 +28,13 @@ public: typedef GrAtlasTextBlob Blob; struct Geometry { SkMatrix fViewMatrix; - Blob* fBlob; + SkIRect fClipRect; + Blob* fBlob; SkScalar fX; SkScalar fY; - int fRun; - int fSubRun; - GrColor fColor; + int fRun; + int fSubRun; + GrColor fColor; }; static std::unique_ptr<GrAtlasTextOp> MakeBitmap(GrPaint&& paint, GrMaskFormat maskFormat, @@ -173,11 +174,7 @@ private: static constexpr auto kMaxTextures = 4; - // TODO just use class params - sk_sp<GrGeometryProcessor> setupDfProcessor(const SkMatrix& viewMatrix, SkColor luminanceColor, - GrColor color, - const sk_sp<GrTextureProxy> [kMaxTextures]) const; - + sk_sp<GrGeometryProcessor> setupDfProcessor() const; // The minimum number of Geometry we will try to allocate. enum { kMinGeometryAllocated = 4 }; diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp index 5d27b3eb69..339ae6de21 100644 --- a/src/gpu/text/GrAtlasTextBlob.cpp +++ b/src/gpu/text/GrAtlasTextBlob.cpp @@ -7,6 +7,7 @@ #include "GrAtlasTextBlob.h" #include "GrBlurUtils.h" +#include "GrClip.h" #include "GrContext.h" #include "GrRenderTargetContext.h" #include "GrTextUtils.h" @@ -258,8 +259,9 @@ bool GrAtlasTextBlob::mustRegenerate(const GrTextUtils::Paint& paint, inline std::unique_ptr<GrDrawOp> GrAtlasTextBlob::makeOp( const Run::SubRunInfo& info, int glyphCount, int run, int subRun, - const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const GrTextUtils::Paint& paint, - const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, + const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipRect, + const GrTextUtils::Paint& paint, const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, GrAtlasGlyphCache* cache, GrRenderTargetContext* renderTargetContext) { GrMaskFormat format = info.maskFormat(); @@ -279,6 +281,7 @@ inline std::unique_ptr<GrDrawOp> GrAtlasTextBlob::makeOp( } GrAtlasTextOp::Geometry& geometry = op->geometry(); geometry.fViewMatrix = viewMatrix; + geometry.fClipRect = clipRect; geometry.fBlob = SkRef(this); geometry.fRun = run; geometry.fSubRun = subRun; @@ -302,10 +305,33 @@ inline void GrAtlasTextBlob::flushRun(GrRenderTargetContext* rtc, const GrClip& if (0 == glyphCount) { continue; } - auto op = this->makeOp(info, glyphCount, run, subRun, viewMatrix, x, y, std::move(paint), - props, distanceAdjustTable, cache, rtc); + + SkRect rtBounds = SkRect::MakeWH(rtc->width(), rtc->height()); + SkRRect clipRRect; + GrAA aa; + // we can clip geometrically if we're not using SDFs, + // and we have an axis-aligned rectangular non-AA clip + bool skipClip = false; + SkIRect clipRect = SkIRect::MakeEmpty(); + if (!info.drawAsDistanceFields() && clip.isRRect(rtBounds, &clipRRect, &aa) && + clipRRect.isRect() && GrAA::kNo == aa) { + skipClip = true; + // we only need to do clipping work if the subrun isn't contained by the clip + SkRect subRunBounds; + this->computeSubRunBounds(&subRunBounds, run, subRun, viewMatrix, x, y); + if (!clipRRect.getBounds().contains(subRunBounds)) { + clipRRect.getBounds().round(&clipRect); + } + } + + auto op = this->makeOp(info, glyphCount, run, subRun, viewMatrix, x, y, clipRect, + std::move(paint), props, distanceAdjustTable, cache, rtc); if (op) { - rtc->addDrawOp(clip, std::move(op)); + if (skipClip) { + rtc->addDrawOp(GrNoClip(), std::move(op)); + } else { + rtc->addDrawOp(clip, std::move(op)); + } } } } @@ -427,8 +453,9 @@ std::unique_ptr<GrDrawOp> GrAtlasTextBlob::test_makeOp( const GrDistanceFieldAdjustTable* distanceAdjustTable, GrAtlasGlyphCache* cache, GrRenderTargetContext* rtc) { const GrAtlasTextBlob::Run::SubRunInfo& info = fRuns[run].fSubRunInfo[subRun]; - return this->makeOp(info, glyphCount, run, subRun, viewMatrix, x, y, paint, props, - distanceAdjustTable, cache, rtc); + SkIRect emptyRect = SkIRect::MakeEmpty(); + return this->makeOp(info, glyphCount, run, subRun, viewMatrix, x, y, emptyRect, + paint, props, distanceAdjustTable, cache, rtc); } void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlob& r) { diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h index e300c66319..11f8505720 100644 --- a/src/gpu/text/GrAtlasTextBlob.h +++ b/src/gpu/text/GrAtlasTextBlob.h @@ -240,8 +240,8 @@ public: // The color here is the GrPaint color, and it is used to determine whether we // have to regenerate LCD text blobs. // We use this color vs the SkPaint color because it has the colorfilter applied. - void initReusableBlob(SkColor luminanceColor, const SkMatrix& viewMatrix, SkScalar x, - SkScalar y) { + void initReusableBlob(SkColor luminanceColor, const SkMatrix& viewMatrix, + SkScalar x, SkScalar y) { fLuminanceColor = luminanceColor; this->setupViewMatrix(viewMatrix, x, y); } @@ -463,7 +463,7 @@ private: GrColor fColor; GrMaskFormat fMaskFormat; uint32_t fFlags; - }; + }; // SubRunInfo SubRunInfo& push_back() { // Forward glyph / vertex information to seed the new sub run @@ -490,7 +490,7 @@ private: std::unique_ptr<SkAutoDescriptor> fOverrideDescriptor; // df properties bool fInitialized; bool fDrawAsPaths; - }; + }; // Run template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs> void regenInOp(GrDrawOp::Target* target, GrAtlasGlyphCache* fontCache, GrBlobRegenHelper* helper, @@ -498,8 +498,9 @@ private: size_t vertexStride, GrColor color, SkScalar transX, SkScalar transY) const; inline std::unique_ptr<GrDrawOp> makeOp(const Run::SubRunInfo& info, int glyphCount, int run, - int subRun, const SkMatrix& viewMatrix, SkScalar x, - SkScalar y, const GrTextUtils::Paint& paint, + int subRun, const SkMatrix& viewMatrix, + SkScalar x, SkScalar y, const SkIRect& clipRect, + const GrTextUtils::Paint& paint, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, GrAtlasGlyphCache* cache, GrRenderTargetContext*); diff --git a/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp b/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp index 2d373ad4a0..c551a2aa31 100644 --- a/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp +++ b/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp @@ -199,8 +199,8 @@ void GrAtlasTextBlob::regenInOp(GrDrawOp::Target* target, GrAtlasGlyphCache* fon } regen_vertices<regenPos, regenCol, regenTexCoords>(vertex, glyph, vertexStride, - info->drawAsDistanceFields(), transX, - transY, color); + info->drawAsDistanceFields(), + transX, transY, color); vertex += vertexStride * GrAtlasTextOp::kVerticesPerGlyph; helper->incGlyphCount(); } diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp index 3ddf4ff69d..8f310d037c 100644 --- a/src/gpu/text/GrAtlasTextContext.cpp +++ b/src/gpu/text/GrAtlasTextContext.cpp @@ -163,7 +163,8 @@ void GrAtlasTextContext::RegenerateTextBlob(GrAtlasTextBlob* cacheBlob, GrAtlasGlyphCache* fontCache, const GrShaderCaps& shaderCaps, const GrTextUtils::Paint& paint, - uint32_t scalerContextFlags, const SkMatrix& viewMatrix, + uint32_t scalerContextFlags, + const SkMatrix& viewMatrix, const SkSurfaceProps& props, const SkTextBlob* blob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter) { cacheBlob->initReusableBlob(paint.luminanceColor(), viewMatrix, x, y); diff --git a/src/gpu/text/GrTextUtils.cpp b/src/gpu/text/GrTextUtils.cpp index c6ae5b141b..7ad4b4a76b 100644 --- a/src/gpu/text/GrTextUtils.cpp +++ b/src/gpu/text/GrTextUtils.cpp @@ -181,7 +181,6 @@ void GrTextUtils::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, int x = vx + glyph->fBounds.fLeft; int y = vy + glyph->fBounds.fTop; - // keep them as ints until we've done the clip-test int width = glyph->fBounds.width(); int height = glyph->fBounds.height(); |