Add blendmode to GrRTC::drawTexture
This makes drawTexture handle blend modes with a fallback to be consistent
with drawTextureSet. Simple draws (other than non src-over) should be
faster now since they will skip the extra overhead of the GrTextureAdjuster.
It also refactors the GrPaint emulation of GrTextureOp into a function,
which will be reused in the general-purpose quad APIs.
Bug: skia:
Change-Id: Idad67ec749b82c6894df6ec2b57987130125b910
Reviewed-on: https://skia-review.googlesource.com/c/191360
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
diff --git a/gm/clockwise.cpp b/gm/clockwise.cpp
index a8a201f..a93a94e 100644
--- a/gm/clockwise.cpp
+++ b/gm/clockwise.cpp
@@ -154,7 +154,8 @@
topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()),
- GrSamplerState::Filter::kNearest, SK_PMColor4fWHITE, {0, 0, 100, 200},
+ GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
+ SK_PMColor4fWHITE, {0, 0, 100, 200},
{100, 0, 200, 200}, GrQuadAAFlags::kNone,
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
nullptr);
@@ -170,7 +171,8 @@
topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()),
- GrSamplerState::Filter::kNearest, SK_PMColor4fWHITE, {0, 0, 100, 200},
+ GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
+ SK_PMColor4fWHITE, {0, 0, 100, 200},
{200, 0, 300, 200}, GrQuadAAFlags::kNone,
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
nullptr);
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 21bfebd..b66d0ad 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -37,6 +37,7 @@
#include "SkShadowUtils.h"
#include "SkSurfacePriv.h"
#include "effects/GrRRectEffect.h"
+#include "effects/GrTextureDomain.h"
#include "ops/GrAtlasTextOp.h"
#include "ops/GrClearOp.h"
#include "ops/GrClearStencilClipOp.h"
@@ -937,10 +938,30 @@
viewMatrix, croppedRect));
}
+// Creates a paint for GrFillRectOp that matches behavior of GrTextureOp
+static void draw_texture_to_grpaint(sk_sp<GrTextureProxy> proxy, const SkRect* domain,
+ GrSamplerState::Filter filter, SkBlendMode mode,
+ const SkPMColor4f& color, sk_sp<GrColorSpaceXform> csXform,
+ GrPaint* paint) {
+ paint->setColor4f(color);
+ paint->setXPFactory(SkBlendMode_AsXPFactory(mode));
+
+ std::unique_ptr<GrFragmentProcessor> fp;
+ if (domain) {
+ fp = GrTextureDomainEffect::Make(std::move(proxy), SkMatrix::I(), *domain,
+ GrTextureDomain::kClamp_Mode, filter);
+ } else {
+ fp = GrSimpleTextureEffect::Make(std::move(proxy), SkMatrix::I(), filter);
+ }
+
+ fp = GrColorSpaceXformEffect::Make(std::move(fp), csXform);
+ paint->addColorFragmentProcessor(std::move(fp));
+}
+
void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
- GrSamplerState::Filter filter, const SkPMColor4f& color,
- const SkRect& srcRect, const SkRect& dstRect,
- GrQuadAAFlags aaFlags,
+ GrSamplerState::Filter filter, SkBlendMode mode,
+ const SkPMColor4f& color, const SkRect& srcRect,
+ const SkRect& dstRect, GrQuadAAFlags aaFlags,
SkCanvas::SrcRectConstraint constraint,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
@@ -952,6 +973,7 @@
srcRect.contains(proxy->getWorstCaseBoundsRect())) {
constraint = SkCanvas::kFast_SrcRectConstraint;
}
+
GrAAType aaType =
this->chooseAAType(GrAA(aaFlags != GrQuadAAFlags::kNone), GrAllowMixedSamples::kNo);
SkRect clippedDstRect = dstRect;
@@ -960,9 +982,37 @@
&clippedSrcRect)) {
return;
}
- auto op = GrTextureOp::Make(fContext, std::move(proxy), filter, color, clippedSrcRect,
- clippedDstRect, aaType, aaFlags, constraint, viewMatrix,
- std::move(textureColorSpaceXform));
+
+ AutoCheckFlush acf(this->drawingManager());
+
+ std::unique_ptr<GrDrawOp> op;
+ if (mode != SkBlendMode::kSrcOver) {
+ // Emulation mode with GrPaint and GrFillRectOp
+ if (filter != GrSamplerState::Filter::kNearest &&
+ !GrTextureOp::GetFilterHasEffect(viewMatrix, clippedSrcRect, clippedDstRect)) {
+ filter = GrSamplerState::Filter::kNearest;
+ }
+
+ SkRect domain = srcRect;
+ if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
+ filter == GrSamplerState::Filter::kBilerp) {
+ // Inset by 1/2 pixel, which GrTextureOp and GrTextureAdjuster handle automatically
+ domain.inset(0.5f, 0.5f);
+ }
+
+ GrPaint paint;
+ draw_texture_to_grpaint(std::move(proxy),
+ constraint == SkCanvas::kStrict_SrcRectConstraint ? &domain : nullptr,
+ filter, mode, color, std::move(textureColorSpaceXform), &paint);
+ op = GrFillRectOp::MakePerEdgeWithLocalRect(fContext, std::move(paint), aaType, aaFlags,
+ viewMatrix, clippedDstRect, clippedSrcRect);
+ } else {
+ // Can use a lighter weight op that can chain across proxies
+ op = GrTextureOp::Make(fContext, std::move(proxy), filter, color, clippedSrcRect,
+ clippedDstRect, aaType, aaFlags, constraint, viewMatrix,
+ std::move(textureColorSpaceXform));
+ }
+
this->addDrawOp(clip, std::move(op));
}
@@ -975,35 +1025,19 @@
SkDEBUGCODE(this->validate();)
GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureSet", fContext);
- AutoCheckFlush acf(this->drawingManager());
-
- GrAAType aaType = this->chooseAAType(GrAA::kYes, GrAllowMixedSamples::kNo);
if (mode != SkBlendMode::kSrcOver ||
!fContext->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
// Draw one at a time with GrFillRectOp and a GrPaint that emulates what GrTextureOp does
- const GrXPFactory* xpFactory = SkBlendMode_AsXPFactory(mode);
for (int i = 0; i < cnt; ++i) {
- GrPaint paint;
- paint.setColor4f({set[i].fAlpha, set[i].fAlpha, set[i].fAlpha, set[i].fAlpha});
- paint.setXPFactory(xpFactory);
-
- // See if we can disable bilerp filtering when the src and dst rects line up
- if (filter != GrSamplerState::Filter::kNearest &&
- !GrTextureOp::GetFilterHasEffect(viewMatrix, set[i].fSrcRect, set[i].fDstRect)) {
- filter = GrSamplerState::Filter::kNearest;
- }
-
- auto fp = GrSimpleTextureEffect::Make(set[i].fProxy, SkMatrix::I(), filter);
- fp = GrColorSpaceXformEffect::Make(std::move(fp), texXform);
- paint.addColorFragmentProcessor(std::move(fp));
-
- auto op = GrFillRectOp::MakePerEdgeWithLocalRect(fContext, std::move(paint), aaType,
- set[i].fAAFlags, viewMatrix,
- set[i].fDstRect, set[i].fSrcRect);
- this->addDrawOp(clip, std::move(op));
+ 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,
+ 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);
auto op = GrTextureOp::Make(fContext, set, cnt, filter, aaType, viewMatrix,
std::move(texXform));
this->addDrawOp(clip, std::move(op));
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index a4b329e..7854ab0 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -152,9 +152,9 @@
* device space.
*/
void drawTexture(const GrClip& clip, sk_sp<GrTextureProxy>, GrSamplerState::Filter,
- const SkPMColor4f&, const SkRect& srcRect, const SkRect& dstRect,
- GrQuadAAFlags, SkCanvas::SrcRectConstraint, const SkMatrix& viewMatrix,
- sk_sp<GrColorSpaceXform> texXform);
+ SkBlendMode mode, const SkPMColor4f&, const SkRect& srcRect,
+ const SkRect& dstRect, GrQuadAAFlags, SkCanvas::SrcRectConstraint,
+ const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> texXform);
/** Used with drawTextureSet */
struct TextureSetEntry {
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp
index f1a0424..da8d9ed 100644
--- a/src/gpu/SkGpuDevice_drawTexture.cpp
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp
@@ -93,8 +93,7 @@
*/
static bool can_use_draw_texture(const SkPaint& paint) {
return (!paint.getColorFilter() && !paint.getShader() && !paint.getMaskFilter() &&
- !paint.getImageFilter() && paint.getFilterQuality() < kMedium_SkFilterQuality &&
- paint.getBlendMode() == SkBlendMode::kSrcOver);
+ !paint.getImageFilter() && paint.getFilterQuality() < kMedium_SkFilterQuality);
}
static void draw_texture(const SkPaint& paint, const SkMatrix& ctm, const SkRect* src,
@@ -127,6 +126,21 @@
case kHigh_SkFilterQuality:
SK_ABORT("Quality level not allowed.");
}
+
+ // Must specify the strict constraint when the proxy is not functionally exact and the src
+ // rect would access pixels outside the proxy's content area without the constraint.
+ if (constraint != SkCanvas::kStrict_SrcRectConstraint &&
+ !GrProxyProvider::IsFunctionallyExact(proxy.get())) {
+ // Conservative estimate of how much a coord could be outset from src rect:
+ // 1/2 pixel for AA and 1/2 pixel for bilerp
+ float buffer = 0.5f * (aa == GrAA::kYes) +
+ 0.5f * (filter == GrSamplerState::Filter::kBilerp);
+ SkRect safeBounds = SkRect::MakeWH(proxy->width(), proxy->height());
+ safeBounds.inset(buffer, buffer);
+ if (!safeBounds.contains(srcRect)) {
+ constraint = SkCanvas::kStrict_SrcRectConstraint;
+ }
+ }
SkPMColor4f color;
if (GrPixelConfigIsAlphaOnly(proxy->config())) {
color = SkColor4fPrepForDst(paint.getColor4f(), dstInfo, *rtc->caps()).premul();
@@ -135,8 +149,8 @@
color = { paintAlpha, paintAlpha, paintAlpha, paintAlpha };
}
GrQuadAAFlags aaFlags = aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
- rtc->drawTexture(clip, std::move(proxy), filter, color, srcRect, dstRect, aaFlags, constraint,
- ctm, std::move(textureXform));
+ rtc->drawTexture(clip, std::move(proxy), filter, paint.getBlendMode(), color, srcRect, dstRect,
+ aaFlags, constraint, ctm, std::move(textureXform));
}
//////////////////////////////////////////////////////////////////////////////
diff --git a/tests/GrSurfaceTest.cpp b/tests/GrSurfaceTest.cpp
index 95f3794..39c6d76 100644
--- a/tests/GrSurfaceTest.cpp
+++ b/tests/GrSurfaceTest.cpp
@@ -472,10 +472,10 @@
GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo,
GrInternalSurfaceFlags ::kNone, SkBackingFit::kExact, budgeted,
GrSurfaceProxy::LazyInstantiationType::kSingleUse);
- rtc->drawTexture(GrNoClip(), proxy, GrSamplerState::Filter::kNearest, SkPMColor4f(),
- SkRect::MakeWH(kS, kS), SkRect::MakeWH(kS, kS),
- GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
- SkMatrix::I(), nullptr);
+ rtc->drawTexture(GrNoClip(), proxy, GrSamplerState::Filter::kNearest,
+ SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(kS, kS),
+ SkRect::MakeWH(kS, kS), GrQuadAAFlags::kNone,
+ SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
// We still have the proxy, which should remain instantiated, thereby keeping the
// texture not purgeable.
REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
@@ -486,9 +486,9 @@
// This time we move the proxy into the draw.
rtc->drawTexture(GrNoClip(), std::move(proxy), GrSamplerState::Filter::kNearest,
- SkPMColor4f(), SkRect::MakeWH(kS, kS), SkRect::MakeWH(kS, kS),
- GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
- SkMatrix::I(), nullptr);
+ SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(kS, kS),
+ SkRect::MakeWH(kS, kS), GrQuadAAFlags::kNone,
+ SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
context->flush();
context->priv().getGpu()->testingOnly_flushGpuAndSync();
@@ -505,9 +505,9 @@
GrInternalSurfaceFlags ::kNone, SkBackingFit::kExact, budgeted,
GrSurfaceProxy::LazyInstantiationType::kDeinstantiate);
rtc->drawTexture(GrNoClip(), std::move(proxy), GrSamplerState::Filter::kNearest,
- SkPMColor4f(), SkRect::MakeWH(kS, kS), SkRect::MakeWH(kS, kS),
- GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
- SkMatrix::I(), nullptr);
+ SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(kS, kS),
+ SkRect::MakeWH(kS, kS), 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.
REPORTER_ASSERT(reporter, idleIDs.find(3) == idleIDs.end());
@@ -552,8 +552,9 @@
auto proxy = context->priv().proxyProvider()->testingOnly_createWrapped(
texture, kTopLeft_GrSurfaceOrigin);
rtc->drawTexture(GrNoClip(), proxy, GrSamplerState::Filter::kNearest,
- SkPMColor4f(), SkRect::MakeWH(kS, kS),
- SkRect::MakeWH(kS, kS), GrQuadAAFlags::kNone,
+ SkBlendMode::kSrcOver, SkPMColor4f(),
+ SkRect::MakeWH(kS, kS), SkRect::MakeWH(kS, kS),
+ GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
nullptr);
if (drawType == DrawType::kDrawAndFlush) {