move GrAtlasTextOp creation to GrRenderTargetContext

The op creation is no self contained, which means that it handles
taking the clip. For random op testing, this means that some times
no op is created for blobs that are entirely off screen. This
results in a nullptr op. The random op test has been adjust accordingly.

Change-Id: I619ffb315b7ad7c834b3e85d7120fe2cdb90c56a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/301583
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Herb Derby 2020-07-09 16:02:08 -04:00 committed by Skia Commit-Bot
parent 54867de4bf
commit 411e7aa8b1
6 changed files with 173 additions and 179 deletions

View File

@ -47,6 +47,7 @@
#include "src/gpu/GrTracing.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/effects/GrBicubicEffect.h"
#include "src/gpu/effects/GrDistanceFieldGeoProc.h"
#include "src/gpu/effects/GrRRectEffect.h"
#include "src/gpu/geometry/GrQuad.h"
#include "src/gpu/geometry/GrQuadUtils.h"
@ -479,8 +480,139 @@ void GrRenderTargetContext::drawTextPaths(const GrClip* clip,
}
}
static SkPMColor4f generate_filtered_color(const SkPaint& paint, const GrColorInfo& colorInfo) {
SkColor4f c = paint.getColor4f();
if (auto* xform = colorInfo.colorSpaceXformFromSRGB()) {
c = xform->apply(c);
}
if (auto* cf = paint.getColorFilter()) {
c = cf->filterColor4f(c, colorInfo.colorSpace(), colorInfo.colorSpace());
}
return c.premul();
}
std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>>
GrRenderTargetContext::makeAtlasTextOp(const GrClip* clip,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList,
GrTextBlob::SubRun* subRun) {
SkASSERT(subRun->glyphCount() != 0);
SkPoint drawOrigin = glyphRunList.origin();
const SkPaint& drawPaint = glyphRunList.paint();
const SkMatrix& drawMatrix = viewMatrix.localToDevice();
GrRecordingContext* context = this->fContext;
GrOpMemoryPool* pool = context->priv().opMemoryPool();
const GrColorInfo& colorInfo = this->colorInfo();
// We can clip geometrically using clipRect and ignore clip if we're not using SDFs or
// transformed glyphs, and we have an axis-aligned rectangular non-AA clip.
std::unique_ptr<GrDrawOp> op;
if (!subRun->drawAsDistanceFields()) {
SkIRect clipRect = SkIRect::MakeEmpty();
if (!subRun->needsTransform()) {
// We only need to do clipping work if the SubRun isn't contained by the clip
SkRect subRunBounds = subRun->deviceRect(drawMatrix, drawOrigin);
SkRect renderTargetBounds = SkRect::MakeWH(this->width(), this->height());
if (clip == nullptr && !renderTargetBounds.intersects(subRunBounds)) {
// If the SubRun is completely outside, don't add an op for it.
return {nullptr, nullptr};
} else if (clip != nullptr) {
GrClip::PreClipResult result = clip->preApply(subRunBounds);
if (result.fEffect == GrClip::Effect::kClipped) {
if (result.fIsRRect && result.fRRect.isRect() &&
result.fAA == GrAA::kNo) {
// Clip geometrically during onPrepare using clipRect.
result.fRRect.getBounds().round(&clipRect);
clip = nullptr;
}
} else if (result.fEffect == GrClip::Effect::kClippedOut) {
return {nullptr, nullptr};
}
}
}
if (!clipRect.isEmpty()) { SkASSERT(clip == nullptr); }
// Produce the Bitmap Op.
GrPaint grPaint;
if (kARGB_GrMaskFormat == subRun->maskFormat()) {
SkPaintToGrPaintWithPrimitiveColor(
context, colorInfo, drawPaint, viewMatrix, &grPaint);
} else {
SkPaintToGrPaint(context, colorInfo, drawPaint, viewMatrix, &grPaint);
}
// This is the color the op will use to draw.
SkPMColor4f drawingColor = generate_filtered_color(drawPaint, colorInfo);
GrAtlasTextOp::MaskType maskType = [&]() {
switch (subRun->maskFormat()) {
case kA8_GrMaskFormat: return GrAtlasTextOp::kGrayscaleCoverageMask_MaskType;
case kA565_GrMaskFormat: return GrAtlasTextOp::kLCDCoverageMask_MaskType;
case kARGB_GrMaskFormat: return GrAtlasTextOp::kColorBitmapMask_MaskType;
// Needed to placate some compilers.
default: return GrAtlasTextOp::kGrayscaleCoverageMask_MaskType;
}
}();
op = pool->allocate<GrAtlasTextOp>(maskType,
std::move(grPaint),
subRun,
drawMatrix,
drawOrigin,
clipRect,
drawingColor,
0,
false,
0);
} else {
GrPaint grPaint;
SkPaintToGrPaint(context, colorInfo, drawPaint, viewMatrix, &grPaint);
// This is the color the op will use to draw.
SkPMColor4f drawingColor = generate_filtered_color(drawPaint, colorInfo);
const SkSurfaceProps& props = this->surfaceProps();
bool isBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
bool isLCD = subRun->hasUseLCDText() && SkPixelGeometryIsH(props.pixelGeometry());
using MT = GrAtlasTextOp::MaskType;
MT maskType = !subRun->isAntiAliased() ? MT::kAliasedDistanceField_MaskType
: isLCD ? (isBGR ? MT::kLCDBGRDistanceField_MaskType
: MT::kLCDDistanceField_MaskType)
: MT::kGrayscaleDistanceField_MaskType;
bool useGammaCorrectDistanceTable = colorInfo.isLinearlyBlended();
uint32_t DFGPFlags = drawMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
DFGPFlags |= drawMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
DFGPFlags |= drawMatrix.hasPerspective() ? kPerspective_DistanceFieldEffectFlag : 0;
DFGPFlags |= useGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
DFGPFlags |= MT::kAliasedDistanceField_MaskType == maskType ?
kAliased_DistanceFieldEffectFlag : 0;
if (isLCD) {
DFGPFlags |= kUseLCD_DistanceFieldEffectFlag;
DFGPFlags |= MT::kLCDBGRDistanceField_MaskType == maskType ?
kBGR_DistanceFieldEffectFlag : 0;
}
op = pool->allocate<GrAtlasTextOp>(maskType,
std::move(grPaint),
subRun,
drawMatrix,
drawOrigin,
SkIRect::MakeEmpty(),
drawingColor,
SkPaintPriv::ComputeLuminanceColor(drawPaint),
useGammaCorrectDistanceTable,
DFGPFlags);
}
return {clip, std::move(op)};
}
void GrRenderTargetContext::drawGlyphRunList(const GrClip* clip,
const SkMatrixProvider& matrixProvider,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
@ -536,7 +668,7 @@ void GrRenderTargetContext::drawGlyphRunList(const GrClip* clip,
blob = textBlobCache->find(key);
}
const SkMatrix& drawMatrix(matrixProvider.localToDevice());
const SkMatrix& drawMatrix(viewMatrix.localToDevice());
if (blob != nullptr && blob->canReuse(blobPaint, blurRec, drawMatrix, drawOrigin)) {
// Reusing the blob. Move it to the front of LRU cache.
textBlobCache->makeMRU(blob.get());
@ -560,58 +692,11 @@ void GrRenderTargetContext::drawGlyphRunList(const GrClip* clip,
for (GrTextBlob::SubRun* subRun : blob->subRunList()) {
if (subRun->drawAsPaths()) {
this->drawTextPaths(clip, matrixProvider, glyphRunList, subRun);
this->drawTextPaths(clip, viewMatrix, glyphRunList, subRun);
} else {
// Handle the mask and distance field cases.
SkASSERT(subRun->glyphCount() != 0);
// We can clip geometrically using clipRect and ignore clip if we're not using SDFs or
// transformed glyphs, and we have an axis-aligned rectangular non-AA clip.
std::unique_ptr<GrAtlasTextOp> op;
const GrClip* subRunClip = clip;
if (!subRun->drawAsDistanceFields()) {
SkIRect clipRect = SkIRect::MakeEmpty();
if (!subRun->needsTransform()) {
// We only need to do clipping work if the SubRun isn't contained by the clip
SkRect subRunBounds = subRun->deviceRect(
matrixProvider.localToDevice(), drawOrigin);
SkRect renderTargetBounds = SkRect::MakeWH(this->width(), this->height());
if (subRunClip == nullptr && !renderTargetBounds.intersects(subRunBounds)) {
// If the SubRun is completely outside, don't add an op for it.
continue;
} else if (subRunClip != nullptr) {
GrClip::PreClipResult result = subRunClip->preApply(subRunBounds);
if (result.fEffect == GrClip::Effect::kClipped) {
if (result.fIsRRect && result.fRRect.isRect() &&
result.fAA == GrAA::kNo) {
// Clip geometrically during onPrepare using clipRect.
result.fRRect.getBounds().round(&clipRect);
subRunClip = nullptr;
}
} else if (result.fEffect == GrClip::Effect::kClippedOut) {
continue;
}
}
}
if (!clipRect.isEmpty()) { SkASSERT(subRunClip == nullptr); }
op = GrAtlasTextOp::MakeBitmap(this,
blobPaint,
subRun,
matrixProvider,
drawOrigin,
clipRect);
} else {
op = GrAtlasTextOp::MakeDistanceField(this,
blobPaint,
subRun,
matrixProvider,
drawOrigin);
}
auto [drawingClip, op] = this->makeAtlasTextOp(clip, viewMatrix, glyphRunList, subRun);
if (op != nullptr) {
this->addDrawOp(subRunClip, std::move(op));
this->addDrawOp(drawingClip, std::move(op));
}
}
}

View File

@ -24,6 +24,8 @@
#include "src/gpu/geometry/GrQuad.h"
#include "src/gpu/text/GrTextBlob.h"
#include <tuple>
class GrBackendSemaphore;
class GrClip;
class GrColorSpaceXform;
@ -140,8 +142,6 @@ public:
~GrRenderTargetContext() override;
virtual void drawGlyphRunList(const GrClip*, const SkMatrixProvider&, const SkGlyphRunList&);
/**
* Provides a perfomance hint that the render target's contents are allowed
* to become undefined.
@ -518,6 +518,26 @@ public:
const SkGlyphRunList& glyphRunList,
GrTextBlob::SubRun* subRun);
/**
* Make the AtlasTextOp - returns the op and the original clip or nullptr for the clip if the
* op is going to clip geometrically.
*/
std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>>
makeAtlasTextOp(const GrClip*,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList,
GrTextBlob::SubRun* subRun);
/**
* Draw the text specified by the SkGlyphRunList.
*
* @param viewMatrix transformationMatrix
* @param glyphRunList text, text positions, and paint.
*/
void drawGlyphRunList(const GrClip*,
const SkMatrixProvider& viewMatrix,
const SkGlyphRunList& glyphRunList);
/**
* Draws the src texture with no matrix. The dstRect is the dstPoint with the width and height
* of the srcRect. The srcRect and dstRect are clipped to the bounds of the src and dst surfaces
@ -590,7 +610,6 @@ private:
friend class GrFillRectOp; // for access to addDrawOp
friend class GrTessellationPathRenderer; // for access to addDrawOp
friend class GrTextureOp; // for access to addDrawOp
friend class GrAtlasTextOp; // for access to addDrawOp
SkDEBUGCODE(void onValidate() const override;)

View File

@ -102,6 +102,10 @@ public:
void testingOnly_addDrawOp(const GrClip*, std::unique_ptr<GrDrawOp>,
const std::function<WillAddOpFn>& = std::function<WillAddOpFn>());
SkGlyphRunListPainter* testingOnly_glyphRunPainter() {
return &fRenderTargetContext->fGlyphPainter;
}
bool refsWrappedObjects() const {
return fRenderTargetContext->asRenderTargetProxy()->refsWrappedObjects();
}

View File

@ -75,107 +75,6 @@ void GrAtlasTextOp::Geometry::fillVertexData(void *dst, int offset, int count) c
fDrawMatrix, fDrawOrigin, fClipRect);
}
static SkPMColor4f generate_filtered_color(const SkPaint& paint, const GrColorInfo& colorInfo) {
SkColor4f c = paint.getColor4f();
if (auto* xform = colorInfo.colorSpaceXformFromSRGB()) {
c = xform->apply(c);
}
if (auto* cf = paint.getColorFilter()) {
c = cf->filterColor4f(c, colorInfo.colorSpace(), colorInfo.colorSpace());
}
return c.premul();
}
std::unique_ptr<GrAtlasTextOp> GrAtlasTextOp::MakeBitmap(GrRenderTargetContext* rtc,
const SkPaint& paint,
GrTextBlob::SubRun* subrun,
const SkMatrixProvider& matrixProvider,
SkPoint drawOrigin,
const SkIRect& clipRect) {
GrPaint grPaint;
GrRecordingContext* context = rtc->priv().getContext();
const GrColorInfo& colorInfo = rtc->colorInfo();
if (kARGB_GrMaskFormat == subrun->maskFormat()) {
SkPaintToGrPaintWithPrimitiveColor(context, colorInfo, paint, matrixProvider, &grPaint);
} else {
SkPaintToGrPaint(context, colorInfo, paint, matrixProvider, &grPaint);
}
// This is the color the op will use to draw.
SkPMColor4f drawingColor = generate_filtered_color(paint, colorInfo);
GrOpMemoryPool* pool = context->priv().opMemoryPool();
MaskType maskType = [&]() {
switch (subrun->maskFormat()) {
case kA8_GrMaskFormat: return kGrayscaleCoverageMask_MaskType;
case kA565_GrMaskFormat: return kLCDCoverageMask_MaskType;
case kARGB_GrMaskFormat: return kColorBitmapMask_MaskType;
// Needed to placate some compilers.
default: return kGrayscaleCoverageMask_MaskType;
}
}();
return pool->allocate<GrAtlasTextOp>(maskType,
std::move(grPaint),
subrun,
matrixProvider.localToDevice(),
drawOrigin,
clipRect,
drawingColor,
0,
false,
0);
}
std::unique_ptr<GrAtlasTextOp> GrAtlasTextOp::MakeDistanceField(
GrRenderTargetContext* rtc,
const SkPaint& paint,
GrTextBlob::SubRun* subrun,
const SkMatrixProvider& matrixProvider,
SkPoint drawOrigin) {
GrPaint grPaint;
GrRecordingContext* context = rtc->priv().getContext();
const GrColorInfo& colorInfo = rtc->colorInfo();
SkPaintToGrPaint(context, colorInfo, paint, matrixProvider, &grPaint);
// This is the color the op will use to draw.
SkPMColor4f drawingColor = generate_filtered_color(paint, colorInfo);
const SkSurfaceProps& props = rtc->surfaceProps();
GrOpMemoryPool* pool = context->priv().opMemoryPool();
bool isBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
bool isLCD = subrun->hasUseLCDText() && SkPixelGeometryIsH(props.pixelGeometry());
MaskType maskType = !subrun->isAntiAliased() ? kAliasedDistanceField_MaskType
: isLCD ? (isBGR ? kLCDBGRDistanceField_MaskType
: kLCDDistanceField_MaskType)
: kGrayscaleDistanceField_MaskType;
const SkMatrix& drawMatrix = matrixProvider.localToDevice();
bool useGammaCorrectDistanceTable = colorInfo.isLinearlyBlended();
uint32_t DFGPFlags = drawMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
DFGPFlags |= drawMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
DFGPFlags |= drawMatrix.hasPerspective() ? kPerspective_DistanceFieldEffectFlag : 0;
DFGPFlags |= useGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
DFGPFlags |= kAliasedDistanceField_MaskType == maskType ? kAliased_DistanceFieldEffectFlag : 0;
if (isLCD) {
DFGPFlags |= kUseLCD_DistanceFieldEffectFlag;
DFGPFlags |= kLCDBGRDistanceField_MaskType == maskType ? kBGR_DistanceFieldEffectFlag : 0;
}
return pool->allocate<GrAtlasTextOp>(maskType,
std::move(grPaint),
subrun,
drawMatrix,
drawOrigin,
SkIRect::MakeEmpty(),
drawingColor,
SkPaintPriv::ComputeLuminanceColor(paint),
useGammaCorrectDistanceTable,
DFGPFlags);
}
void GrAtlasTextOp::visitProxies(const VisitProxyFunc& func) const {
fProcessors.visitProxies(func);
}
@ -595,11 +494,11 @@ std::unique_ptr<GrDrawOp> GrAtlasTextOp::CreateOpTestingOnly(GrRenderTargetConte
return nullptr;
}
const GrRecordingContextPriv& contextPriv = rtc->fContext->priv();
GrSDFTOptions SDFOptions = rtc->fContext->priv().SDFTOptions();
const GrRecordingContextPriv& contextPriv = rtc->priv().getContext()->priv();
GrSDFTOptions SDFOptions = contextPriv.SDFTOptions();
sk_sp<GrTextBlob> blob = GrTextBlob::Make(glyphRunList, drawMatrix);
SkGlyphRunListPainter* painter = &rtc->fGlyphPainter;
SkGlyphRunListPainter* painter = rtc->priv().testingOnly_glyphRunPainter();
painter->processGlyphRunList(
glyphRunList, drawMatrix, rtc->surfaceProps(),
contextPriv.caps()->shaderCaps()->supportsDistanceFieldText(),
@ -608,12 +507,10 @@ std::unique_ptr<GrDrawOp> GrAtlasTextOp::CreateOpTestingOnly(GrRenderTargetConte
return nullptr;
}
return GrAtlasTextOp::MakeBitmap(rtc,
skPaint,
blob->firstSubRun(),
mtxProvider,
drawOrigin,
SkIRect::MakeEmpty());
std::unique_ptr<GrDrawOp> op;
std::tie(std::ignore, op) =
rtc->makeAtlasTextOp(nullptr, mtxProvider, glyphRunList, blob->firstSubRun());
return op;
}
GR_DRAW_OP_TEST_DEFINE(GrAtlasTextOp) {

View File

@ -37,20 +37,6 @@ public:
void fillVertexData(void* dst, int offset, int count) const;
};
static std::unique_ptr<GrAtlasTextOp> MakeBitmap(GrRenderTargetContext*,
const SkPaint&,
GrTextBlob::SubRun*,
const SkMatrixProvider&,
SkPoint drawOrigin,
const SkIRect& clipRect);
static std::unique_ptr<GrAtlasTextOp> MakeDistanceField(
GrRenderTargetContext*,
const SkPaint&,
GrTextBlob::SubRun*,
const SkMatrixProvider&,
SkPoint drawOrigin);
const char* name() const override { return "AtlasTextOp"; }
void visitProxies(const VisitProxyFunc& func) const override;

View File

@ -200,6 +200,9 @@ void GrDrawRandomOp(SkRandom* random, GrRenderTargetContext* renderTargetContext
uint32_t index = random->nextULessThan(static_cast<uint32_t>(kTotal));
auto op = gFactories[index](
std::move(paint), random, context, renderTargetContext->numSamples());
// Creating a GrAtlasTextOp my not produce an op if for example, it is totally outside the
// render target context.
if (op) {
renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
}