Formalize edge-aa interaction with GrAA

With this formalization, the edge-AA APIs in GrRTC can distinguish
between tiling cases and regular drawing cases implemented using
kNone or kAll for the AA flags. This means fillRectToRect can be
implemented in terms of fillRectWithEdgeAA.

It also means the drawTexture cases will properly handle
isolated draws and tiled draws when drawing into MSAA.

Bug: skia:
Change-Id: I248dd001919228a958cf84b6bc91363b58b72c0b
Reviewed-on: https://skia-review.googlesource.com/c/192023
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Michael Ludwig 2019-02-19 11:44:41 -05:00 committed by Skia Commit-Bot
parent 43f0df33b3
commit 136f45a636
8 changed files with 81 additions and 67 deletions

View File

@ -160,7 +160,7 @@ void ClockwiseGM::onDraw(GrContext* ctx, GrRenderTargetContext* rtc, SkCanvas* c
rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()),
GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
SK_PMColor4fWHITE, {0, 0, 100, 200},
{100, 0, 200, 200}, GrQuadAAFlags::kNone,
{100, 0, 200, 200}, GrAA::kNo, GrQuadAAFlags::kNone,
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
nullptr);
}
@ -177,7 +177,7 @@ void ClockwiseGM::onDraw(GrContext* ctx, GrRenderTargetContext* rtc, SkCanvas* c
rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()),
GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
SK_PMColor4fWHITE, {0, 0, 100, 200},
{200, 0, 300, 200}, GrQuadAAFlags::kNone,
{200, 0, 300, 200}, GrAA::kNo, GrQuadAAFlags::kNone,
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
nullptr);
}

View File

@ -66,7 +66,7 @@ static void draw_gradient_tiles(SkCanvas* canvas, bool alignGradients) {
SkMatrix view = canvas->getTotalMatrix();
GrPaint grPaint;
SkPaintToGrPaint(context, rtc->colorSpaceInfo(), paint, view, &grPaint);
rtc->fillRectWithEdgeAA(GrNoClip(), std::move(grPaint),
rtc->fillRectWithEdgeAA(GrNoClip(), std::move(grPaint), GrAA::kYes,
static_cast<GrQuadAAFlags>(aa), view, tile);
} else {
// Fallback to solid color on raster backend since the public API only has color

View File

@ -319,6 +319,22 @@ enum class GrAllowMixedSamples : bool { kNo = false, kYes = true };
GrAAType GrChooseAAType(GrAA, GrFSAAType, GrAllowMixedSamples, const GrCaps&);
/**
* A number of rectangle/quadrilateral drawing APIs can control anti-aliasing on a per edge basis.
* These masks specify which edges are AA'ed. The intent for this is to support tiling with seamless
* boundaries, where the inner edges are non-AA and the outer edges are AA. Regular draws (where AA
* is specified by GrAA) is almost equivalent to kNone or kAll, with the exception of how MSAA is
* handled.
*
* When tiling and there is MSAA, mixed edge rectangles are processed with MSAA, so in order for the
* tiled edges to remain seamless, inner tiles with kNone must also be processed with MSAA. In
* regular drawing, however, kNone should disable MSAA (if it's supported) to match the expected
* appearance.
*
* Therefore, APIs that use per-edge AA flags also take a GrAA value so that they can differentiate
* between the regular and tiling use case behaviors. Tiling operations should always pass
* GrAA::kYes while regular options should pass GrAA based on the SkPaint's anti-alias state.
*/
enum class GrQuadAAFlags {
kLeft = SkCanvas::kLeft_QuadAAFlag,
kTop = SkCanvas::kTop_QuadAAFlag,

View File

@ -881,60 +881,51 @@ bool GrRenderTargetContextPriv::drawAndStencilRect(const GrHardClip& clip,
return true;
}
void GrRenderTargetContext::fillRectToRect(const GrClip& clip,
GrPaint&& paint,
GrAA aa,
const SkMatrix& viewMatrix,
const SkRect& rectToDraw,
const SkRect& localRect) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
SkDEBUGCODE(this->validate();)
GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectToRect", fContext);
SkRect croppedRect = rectToDraw;
SkRect croppedLocalRect = localRect;
if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix,
&croppedRect, &croppedLocalRect)) {
return;
}
AutoCheckFlush acf(this->drawingManager());
GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
this->addDrawOp(clip, GrFillRectOp::MakeWithLocalRect(fContext, std::move(paint), aaType,
viewMatrix, croppedRect, croppedLocalRect));
}
void GrRenderTargetContext::fillRectWithEdgeAA(const GrClip& clip, GrPaint&& paint,
void GrRenderTargetContext::fillRectWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa,
GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix,
const SkRect& rect) {
const SkRect& rect, const SkRect* localRect) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
SkDEBUGCODE(this->validate();)
GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithEdgeAA", fContext);
// If aaType turns into MSAA, make sure to keep quads with no AA edges as MSAA. Sending those
// to drawFilledRect() would have it turn off MSAA in that case, which breaks seaming with
// any partial AA edges that kept MSAA.
GrAAType aaType = this->chooseAAType(GrAA::kYes, GrAllowMixedSamples::kNo);
if (aaType != GrAAType::kMSAA &&
(edgeAA == GrQuadAAFlags::kNone || edgeAA == GrQuadAAFlags::kAll)) {
// This is equivalent to a regular filled rect draw, so route through there to take
// advantage of draw->clear optimizations
this->drawFilledRect(clip, std::move(paint), GrAA(edgeAA == GrQuadAAFlags::kAll),
viewMatrix, rect);
return;
}
GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
std::unique_ptr<GrDrawOp> op;
SkRect croppedRect = rect;
if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
return;
if (localRect) {
// If local coordinates are provided, skip the optimization check to go through
// drawFilledRect, and also calculate clipped local coordinates
SkRect croppedRect = rect;
SkRect croppedLocalRect = *localRect;
if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect,
&croppedLocalRect)) {
return;
}
op = GrFillRectOp::MakePerEdgeWithLocalRect(fContext, std::move(paint), aaType, edgeAA,
viewMatrix, croppedRect, croppedLocalRect);
} else {
// If aaType turns into MSAA, make sure to keep quads with no AA edges as MSAA. Sending
// those to drawFilledRect() would have it turn off MSAA in that case, which breaks seaming
// with any partial AA edges that kept MSAA.
if (aaType != GrAAType::kMSAA &&
(edgeAA == GrQuadAAFlags::kNone || edgeAA == GrQuadAAFlags::kAll)) {
// This is equivalent to a regular filled rect draw, so route through there to take
// advantage of draw->clear optimizations
this->drawFilledRect(clip, std::move(paint), GrAA(edgeAA == GrQuadAAFlags::kAll),
viewMatrix, rect);
return;
}
SkRect croppedRect = rect;
if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
return;
}
op = GrFillRectOp::MakePerEdge(fContext, std::move(paint), aaType, edgeAA, viewMatrix,
croppedRect);
}
AutoCheckFlush acf(this->drawingManager());
this->addDrawOp(clip, GrFillRectOp::MakePerEdge(fContext, std::move(paint), aaType, edgeAA,
viewMatrix, croppedRect));
this->addDrawOp(clip, std::move(op));
}
// Creates a paint for GrFillRectOp that matches behavior of GrTextureOp
@ -960,7 +951,7 @@ static void draw_texture_to_grpaint(sk_sp<GrTextureProxy> proxy, const SkRect* d
void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
GrSamplerState::Filter filter, SkBlendMode mode,
const SkPMColor4f& color, const SkRect& srcRect,
const SkRect& dstRect, GrQuadAAFlags aaFlags,
const SkRect& dstRect, GrAA aa, GrQuadAAFlags aaFlags,
SkCanvas::SrcRectConstraint constraint,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
@ -973,8 +964,7 @@ void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy
constraint = SkCanvas::kFast_SrcRectConstraint;
}
GrAAType aaType =
this->chooseAAType(GrAA(aaFlags != GrQuadAAFlags::kNone), GrAllowMixedSamples::kNo);
GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
SkRect clippedDstRect = dstRect;
SkRect clippedSrcRect = srcRect;
if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &clippedDstRect,
@ -1017,7 +1007,7 @@ void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy
void GrRenderTargetContext::drawTextureSet(const GrClip& clip, const TextureSetEntry set[], int cnt,
GrSamplerState::Filter filter, SkBlendMode mode,
const SkMatrix& viewMatrix,
GrAA aa, const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> texXform) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
@ -1030,13 +1020,13 @@ void GrRenderTargetContext::drawTextureSet(const GrClip& clip, const TextureSetE
for (int i = 0; i < cnt; ++i) {
float alpha = set[i].fAlpha;
this->drawTexture(clip, set[i].fProxy, filter, mode, {alpha, alpha, alpha, alpha},
set[i].fSrcRect, set[i].fDstRect, set[i].fAAFlags,
set[i].fSrcRect, set[i].fDstRect, aa, set[i].fAAFlags,
SkCanvas::kFast_SrcRectConstraint, viewMatrix, texXform);
}
} else {
// Can use a single op, avoiding GrPaint creation, and can batch across proxies
AutoCheckFlush acf(this->drawingManager());
GrAAType aaType = this->chooseAAType(GrAA::kYes, GrAllowMixedSamples::kNo);
GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
auto op = GrTextureOp::MakeSet(fContext, set, cnt, filter, aaType, viewMatrix,
std::move(texXform));
this->addDrawOp(clip, std::move(op));

View File

@ -109,12 +109,16 @@ public:
* @param rectToDraw the rectangle to draw
* @param localRect the rectangle of shader coordinates applied to rectToDraw
*/
void fillRectToRect(const GrClip&,
void fillRectToRect(const GrClip& clip,
GrPaint&& paint,
GrAA,
GrAA aa,
const SkMatrix& viewMatrix,
const SkRect& rectToDraw,
const SkRect& localRect);
const SkRect& localRect) {
this->fillRectWithEdgeAA(clip, std::move(paint), aa,
aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
viewMatrix, rectToDraw, &localRect);
}
/**
* Fills a rect with a paint and a localMatrix.
@ -129,8 +133,9 @@ public:
/**
* Creates an op that draws a fill rect with per-edge control over anti-aliasing.
*/
void fillRectWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix, const SkRect& rect);
void fillRectWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa, GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix, const SkRect& rect,
const SkRect* optionalLocalRect = nullptr);
/** Used with drawQuadSet */
struct QuadSetEntry {
@ -152,7 +157,7 @@ public:
*/
void drawTexture(const GrClip& clip, sk_sp<GrTextureProxy>, GrSamplerState::Filter,
SkBlendMode mode, const SkPMColor4f&, const SkRect& srcRect,
const SkRect& dstRect, GrQuadAAFlags, SkCanvas::SrcRectConstraint,
const SkRect& dstRect, GrAA, GrQuadAAFlags, SkCanvas::SrcRectConstraint,
const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> texXform);
/** Used with drawTextureSet */
@ -168,7 +173,7 @@ public:
* texture color xform. The textures must all have the same GrTextureType and GrConfig.
*/
void drawTextureSet(const GrClip&, const TextureSetEntry[], int cnt, GrSamplerState::Filter,
SkBlendMode mode, const SkMatrix& viewMatrix,
SkBlendMode mode, GrAA aa, const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> texXform);
/**

View File

@ -418,8 +418,9 @@ void SkGpuDevice::drawEdgeAARect(const SkRect& r, SkCanvas::QuadAAFlags aa, SkCo
grPaint.setXPFactory(SkBlendMode_AsXPFactory(mode));
}
// This is exclusively meant for tiling operations, so keep AA enabled to handle MSAA seaming
fRenderTargetContext->fillRectWithEdgeAA(this->clip(), std::move(grPaint),
SkToGrQuadAAFlags(aa), this->ctm(), r);
GrAA::kYes, SkToGrQuadAAFlags(aa), this->ctm(), r);
}
///////////////////////////////////////////////////////////////////////////////
@ -1433,8 +1434,10 @@ void SkGpuDevice::drawImageSet(const SkCanvas::ImageSetEntry set[], int count,
auto textureXform = GrColorSpaceXform::Make(
set[base].fImage->colorSpace(), set[base].fImage->alphaType(),
fRenderTargetContext->colorSpaceInfo().colorSpace(), kPremul_SkAlphaType);
// Currently, drawImageSet is only used for tiled images so keep AA to handle MSAA
// seams (this will not remain true in the future)
fRenderTargetContext->drawTextureSet(this->clip(), textures.get() + base, n,
sampler.filter(), mode, this->ctm(),
sampler.filter(), mode, GrAA::kYes, this->ctm(),
std::move(textureXform));
}
};

View File

@ -150,7 +150,7 @@ static void draw_texture(const SkPaint& paint, const SkMatrix& ctm, const SkRect
}
GrQuadAAFlags aaFlags = aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
rtc->drawTexture(clip, std::move(proxy), filter, paint.getBlendMode(), color, srcRect, dstRect,
aaFlags, constraint, ctm, std::move(textureXform));
aa, aaFlags, constraint, ctm, std::move(textureXform));
}
//////////////////////////////////////////////////////////////////////////////

View File

@ -474,7 +474,7 @@ DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
GrSurfaceProxy::LazyInstantiationType::kSingleUse);
rtc->drawTexture(GrNoClip(), proxy, GrSamplerState::Filter::kNearest,
SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(kS, kS),
SkRect::MakeWH(kS, kS), GrQuadAAFlags::kNone,
SkRect::MakeWH(kS, kS), GrAA::kNo, GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
// We still have the proxy, which should remain instantiated, thereby keeping the
// texture not purgeable.
@ -487,7 +487,7 @@ DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
// This time we move the proxy into the draw.
rtc->drawTexture(GrNoClip(), std::move(proxy), GrSamplerState::Filter::kNearest,
SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(kS, kS),
SkRect::MakeWH(kS, kS), GrQuadAAFlags::kNone,
SkRect::MakeWH(kS, kS), GrAA::kNo, GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
context->flush();
@ -506,7 +506,7 @@ DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
GrSurfaceProxy::LazyInstantiationType::kDeinstantiate);
rtc->drawTexture(GrNoClip(), std::move(proxy), GrSamplerState::Filter::kNearest,
SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(kS, kS),
SkRect::MakeWH(kS, kS), GrQuadAAFlags::kNone,
SkRect::MakeWH(kS, kS), GrAA::kNo, GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
// At this point the proxy shouldn't even be instantiated, there is no texture with
// id 3.
@ -554,7 +554,7 @@ DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
rtc->drawTexture(GrNoClip(), proxy, GrSamplerState::Filter::kNearest,
SkBlendMode::kSrcOver, SkPMColor4f(),
SkRect::MakeWH(kS, kS), SkRect::MakeWH(kS, kS),
GrQuadAAFlags::kNone,
GrAA::kNo, GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
nullptr);
if (drawType == DrawType::kDrawAndFlush) {