diff --git a/docs/SkCanvas_Reference.bmh b/docs/SkCanvas_Reference.bmh index 20b745f2cf..b9a48acd77 100644 --- a/docs/SkCanvas_Reference.bmh +++ b/docs/SkCanvas_Reference.bmh @@ -4957,6 +4957,67 @@ void draw(SkCanvas* canvas) { #Subtopic Lattice ## +# ------------------------------------------------------------------------------ + +#Enum QuadAAFlags +#Line # don't use this ## +#Private +## +#NoExample +## +## + +# ------------------------------------------------------------------------------ + +#Struct ImageSetEntry +#Line # don't use this ## +#Private +## + +#Member SkImage* fImage +#Line # image to draw ## +## + +#Member SkRect fSrcRect +#Line # image src rectangle ## +## + +#Member SkRect fDstRect +#Line # local space rectangle ## +## + +#Member unsigned fAAFlags +#Line # antialiasing flags ## +## + +#NoExample +## + +## + +# ------------------------------------------------------------------------------ + +#Method void experimental_DrawImageSetV0(const ImageSetEntry imageSet[], int cnt, float alpha, + SkFilterQuality quality, SkBlendMode mode); +#Private +## +#In Draw_Image +#In Draw +#Line # draws a set a of images (don't call this) ## + +Draws a set of images. Do not use this method. + +#Param imageSet images ## +#Param cnt number of images ## +#Param alpha alpha ## +#Param quality filter quality ## +#Param mode blend mode ## + +#NoExample +## + +## + #Subtopic Draw_Image ## # ------------------------------------------------------------------------------ diff --git a/experimental/pipe/SkPipeCanvas.cpp b/experimental/pipe/SkPipeCanvas.cpp index 1880697231..93e382bce9 100644 --- a/experimental/pipe/SkPipeCanvas.cpp +++ b/experimental/pipe/SkPipeCanvas.cpp @@ -574,6 +574,22 @@ void SkPipeCanvas::onDrawImageLattice(const SkImage* image, const Lattice& latti } } +void SkPipeCanvas::onDrawImageSet(const ImageSetEntry set[], int count, float alpha, + SkFilterQuality filterQuality, SkBlendMode mode) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawImageSet)); + writer.writeInt(count); + writer.writeScalar(SkFloatToScalar(alpha)); + writer.writeInt((int)filterQuality); + writer.writeInt((int)mode); + for (int i = 0; i < count; ++i) { + writer.writeImage(set[i].fImage.get()); + writer.writeRect(set[i].fSrcRect); + writer.writeRect(set[i].fDstRect); + writer.writeUInt(set[i].fAAFlags); + } +} + /////////////////////////////////////////////////////////////////////////////////////////////////// void SkPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, diff --git a/experimental/pipe/SkPipeCanvas.h b/experimental/pipe/SkPipeCanvas.h index e90a0447b5..f72c6a03d3 100644 --- a/experimental/pipe/SkPipeCanvas.h +++ b/experimental/pipe/SkPipeCanvas.h @@ -133,6 +133,8 @@ protected: const SkPaint*) override; void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst, const SkPaint*) override; + void onDrawImageSet(const ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode) override; void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, const SkPaint&) override; diff --git a/experimental/pipe/SkPipeFormat.h b/experimental/pipe/SkPipeFormat.h index 2b494644ca..f9c5f58942 100644 --- a/experimental/pipe/SkPipeFormat.h +++ b/experimental/pipe/SkPipeFormat.h @@ -45,6 +45,7 @@ enum class SkPipeVerb : uint8_t { kDrawImageRect, // extra == constraint | has_src_rect | has_paint kDrawImageNine, // extra == has_paint:1 kDrawImageLattice, // extra == has_paint:1 + kDrawImageSet, // extra == 0 kDrawVertices, diff --git a/experimental/pipe/SkPipeReader.cpp b/experimental/pipe/SkPipeReader.cpp index 78db5811b0..385119fb07 100644 --- a/experimental/pipe/SkPipeReader.cpp +++ b/experimental/pipe/SkPipeReader.cpp @@ -538,6 +538,23 @@ static void drawImageLattice_handler(SkPipeReader& reader, uint32_t packedVerb, canvas->drawImageLattice(image.get(), lattice, *dst, paint); } +static void drawImageSet_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawImageSet == unpack_verb(packedVerb)); + + int cnt = reader.readInt(); + float alpha = SkScalarToFloat(reader.readScalar()); + SkFilterQuality filterQuality = (SkFilterQuality)reader.readInt(); + SkBlendMode mode = (SkBlendMode)reader.readInt(); + SkAutoTArray set(cnt); + for (int i = 0; i < cnt; ++i) { + set[i].fImage = reader.readImage(); + reader.readRect(&set[i].fSrcRect); + reader.readRect(&set[i].fDstRect); + set[i].fAAFlags = reader.readUInt(); + } + canvas->experimental_DrawImageSetV0(set.get(), cnt, alpha, filterQuality, mode); +} + static void drawVertices_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { SkASSERT(SkPipeVerb::kDrawVertices == unpack_verb(packedVerb)); SkBlendMode bmode = (SkBlendMode)unpack_verb_extra(packedVerb); @@ -735,6 +752,7 @@ const HandlerRec gPipeHandlers[] = { HANDLER(drawImageRect), HANDLER(drawImageNine), HANDLER(drawImageLattice), + HANDLER(drawImageSet), HANDLER(drawVertices), diff --git a/gm/aaflags.cpp b/gm/aaflags.cpp deleted file mode 100644 index 32fbfe3476..0000000000 --- a/gm/aaflags.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "gm.h" - -#include "GrClip.h" -#include "GrContext.h" -#include "GrRenderTargetContext.h" -#include "SkGradientShader.h" -#include "SkImage_Base.h" -#include "SkSurface.h" - -namespace skiagm { - -class AAFlagsGM : public GM { -private: - SkString onShortName() final { return SkString("aaflags"); } - SkISize onISize() override { return SkISize::Make(1000, 1450); } - void onOnceBeforeDraw() override { - static constexpr SkScalar kW = SkIntToScalar(kTileW * kM); - static constexpr SkScalar kH = SkIntToScalar(kTileH * kN); - - auto surf = SkSurface::MakeRaster( - SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); - surf->getCanvas()->clear(SK_ColorLTGRAY); - - static constexpr SkScalar kStripeW = 10; - static constexpr SkScalar kStripeSpacing = 30; - SkPaint paint; - - static constexpr SkPoint pts1[] = {{0.f, 0.f}, {kW, kH}}; - static constexpr SkColor kColors1[] = {SK_ColorCYAN, SK_ColorBLACK}; - auto grad = - SkGradientShader::MakeLinear(pts1, kColors1, nullptr, 2, SkShader::kClamp_TileMode); - paint.setShader(std::move(grad)); - paint.setAntiAlias(true); - paint.setStyle(SkPaint::kStroke_Style); - paint.setStrokeWidth(kStripeW); - SkPoint stripePts[] = {{-kW - kStripeW, -kStripeW}, {kStripeW, kH + kStripeW}}; - while (stripePts[0].fX <= kW) { - surf->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, 2, stripePts, paint); - stripePts[0].fX += kStripeSpacing; - stripePts[1].fX += kStripeSpacing; - } - - static constexpr SkPoint pts2[] = {{0.f, kH}, {kW, 0.f}}; - static constexpr SkColor kColors2[] = {SK_ColorMAGENTA, SK_ColorBLACK}; - grad = SkGradientShader::MakeLinear(pts2, kColors2, nullptr, 2, SkShader::kClamp_TileMode); - paint.setShader(std::move(grad)); - paint.setBlendMode(SkBlendMode::kMultiply); - stripePts[0] = {-kW - kStripeW, kH + kStripeW}; - stripePts[1] = {kStripeW, -kStripeW}; - while (stripePts[0].fX <= kW) { - surf->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, 2, stripePts, paint); - stripePts[0].fX += kStripeSpacing; - stripePts[1].fX += kStripeSpacing; - } - - auto img = surf->makeImageSnapshot(); - for (int y = 0; y < kN; ++y) { - for (int x = 0; x < kM; ++x) { - fImage[x][y] = - img->makeSubset(SkIRect::MakeXYWH(x * kTileW, y * kTileH, kTileW, kTileH)); - } - } - } - - void onDraw(SkCanvas* canvas) override { - GrContext* ctx = canvas->getGrContext(); - if (!ctx) { - DrawGpuOnlyMessage(canvas); - return; - } - GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext(); - SkASSERT(rtc); - - SkScalar d = SkVector{kM * kTileW, kN * kTileH}.length(); - SkMatrix matrices[4]; - // rotation - matrices[0].setRotate(30); - matrices[0].postTranslate(d / 3, 0); - // perespective - SkPoint src[4]; - SkRect::MakeWH(kM * kTileW, kN * kTileH).toQuad(src); - SkPoint dst[4] = {{0, 0}, - {kM * kTileW + 10.f, -5.f}, - {kM * kTileW - 28.f, kN * kTileH + 40.f}, - {45.f, kN * kTileH - 25.f}}; - matrices[1].setPolyToPoly(src, dst, 4); - matrices[1].postTranslate(d, 50.f); - // skew - matrices[2].setRotate(-60.f); - matrices[2].postSkew(0.5f, -1.35f); - matrices[2].postScale(0.6f, 1.05f); - matrices[2].postTranslate(d, 2.5f * d); - // perspective + mirror in x. - dst[1] = {0, 0}; - dst[0] = {3.f / 4.f * kM * kTileW, 0}; - dst[3] = {2.f / 3.f * kM * kTileW, 1 / 4.f * kN * kTileH}; - dst[2] = {1.f / 3.f * kM * kTileW, 1 / 4.f * kN * kTileH - 25.f}; - matrices[3].setPolyToPoly(src, dst, 4); - matrices[3].postTranslate(100.f, d); - for (size_t m = 0; m < SK_ARRAY_COUNT(matrices); ++m) { - // Draw grid of green "lines" at interior tile boundaries. - static constexpr SkScalar kLineOutset = 10.f; - static constexpr SkScalar kLineHalfW = 4.f; - auto color = GrColor4f(0.f, 1.f, 0.f, 1.f); - for (int x = 1; x < kM; ++x) { - GrPaint paint; - paint.setColor4f(color); - SkRect lineRect = - SkRect::MakeLTRB(x * kTileW - kLineHalfW, -kLineOutset, - x * kTileW + kLineHalfW, kN * kTileH + kLineOutset); - rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kYes, matrices[m], lineRect); - } - for (int y = 1; y < kN; ++y) { - GrPaint paint; - paint.setColor4f(color); - SkRect lineRect = - SkRect::MakeLTRB(-kLineOutset, y * kTileH - kLineHalfW, - kTileW * kM + kLineOutset, y * kTileH + kLineHalfW); - rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kYes, matrices[m], lineRect); - } - static constexpr GrColor kColor = GrColor_WHITE; - for (int x = 0; x < kM; ++x) { - for (int y = 0; y < kN; ++y) { - auto proxy = as_IB(fImage[x][y]) - ->asTextureProxyRef(ctx, GrSamplerState::ClampBilerp(), - nullptr, nullptr, nullptr); - if (!proxy) { - continue; - } - auto srcR = proxy->getBoundsRect(); - auto dstR = SkRect::MakeXYWH(x * kTileW, y * kTileH, kTileW, kTileH); - GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone; - if (x == 0) { - aaFlags |= GrQuadAAFlags::kLeft; - } - if (x == kM - 1) { - aaFlags |= GrQuadAAFlags::kRight; - } - if (y == 0) { - aaFlags |= GrQuadAAFlags::kTop; - } - if (y == kN - 1) { - aaFlags |= GrQuadAAFlags::kBottom; - } - rtc->drawTexture(GrNoClip(), proxy, GrSamplerState::Filter::kBilerp, kColor, - srcR, dstR, aaFlags, SkCanvas::kFast_SrcRectConstraint, - matrices[m], nullptr, nullptr); - } - } - } - } - static constexpr int kM = 4; - static constexpr int kN = 4; - static constexpr SkScalar kTileW = 100; - static constexpr SkScalar kTileH = 100; - sk_sp fImage[kM][kN]; -}; - -DEF_GM(return new AAFlagsGM();) - -} // namespace skiagm diff --git a/gm/drawimageset.cpp b/gm/drawimageset.cpp new file mode 100644 index 0000000000..39f9efacc5 --- /dev/null +++ b/gm/drawimageset.cpp @@ -0,0 +1,167 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gm.h" + +#include "SkGradientShader.h" +#include "SkSurface.h" + +namespace skiagm { + +class DrawImageSetGM : public GM { +private: + SkString onShortName() final { return SkString("draw_image_set"); } + SkISize onISize() override { return SkISize::Make(1000, 725); } + void onOnceBeforeDraw() override { + static constexpr SkScalar kW = SkIntToScalar(kTileW * kM); + static constexpr SkScalar kH = SkIntToScalar(kTileH * kN); + + auto surf = SkSurface::MakeRaster( + SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); + surf->getCanvas()->clear(SK_ColorLTGRAY); + + static constexpr SkScalar kStripeW = 10; + static constexpr SkScalar kStripeSpacing = 30; + SkPaint paint; + + static constexpr SkPoint pts1[] = {{0.f, 0.f}, {kW, kH}}; + static constexpr SkColor kColors1[] = {SK_ColorCYAN, SK_ColorBLACK}; + auto grad = + SkGradientShader::MakeLinear(pts1, kColors1, nullptr, 2, SkShader::kClamp_TileMode); + paint.setShader(std::move(grad)); + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(kStripeW); + SkPoint stripePts[] = {{-kW - kStripeW, -kStripeW}, {kStripeW, kH + kStripeW}}; + while (stripePts[0].fX <= kW) { + surf->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, 2, stripePts, paint); + stripePts[0].fX += kStripeSpacing; + stripePts[1].fX += kStripeSpacing; + } + + static constexpr SkPoint pts2[] = {{0.f, kH}, {kW, 0.f}}; + static constexpr SkColor kColors2[] = {SK_ColorMAGENTA, SK_ColorBLACK}; + grad = SkGradientShader::MakeLinear(pts2, kColors2, nullptr, 2, SkShader::kClamp_TileMode); + paint.setShader(std::move(grad)); + paint.setBlendMode(SkBlendMode::kMultiply); + stripePts[0] = {-kW - kStripeW, kH + kStripeW}; + stripePts[1] = {kStripeW, -kStripeW}; + while (stripePts[0].fX <= kW) { + surf->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, 2, stripePts, paint); + stripePts[0].fX += kStripeSpacing; + stripePts[1].fX += kStripeSpacing; + } + + auto img = surf->makeImageSnapshot(); + for (int y = 0; y < kN; ++y) { + for (int x = 0; x < kM; ++x) { + fImage[x][y] = + img->makeSubset(SkIRect::MakeXYWH(x * kTileW, y * kTileH, kTileW, kTileH)); + } + } + } + + void onDraw(SkCanvas* canvas) override { + SkScalar d = SkVector{kM * kTileW, kN * kTileH}.length(); + SkMatrix matrices[4]; + // rotation + matrices[0].setRotate(30); + matrices[0].postTranslate(d / 3, 0); + // perespective + SkPoint src[4]; + SkRect::MakeWH(kM * kTileW, kN * kTileH).toQuad(src); + SkPoint dst[4] = {{0, 0}, + {kM * kTileW + 10.f, -5.f}, + {kM * kTileW - 28.f, kN * kTileH + 40.f}, + {45.f, kN * kTileH - 25.f}}; + SkAssertResult(matrices[1].setPolyToPoly(src, dst, 4)); + matrices[1].postTranslate(d, 50.f); + // skew + matrices[2].setRotate(-60.f); + matrices[2].postSkew(0.5f, -1.15f); + matrices[2].postScale(0.6f, 1.05f); + matrices[2].postTranslate(d, 2.6f * d); + // perspective + mirror in x. + dst[1] = {-.25 * kM * kTileW, 0}; + dst[0] = {5.f / 4.f * kM * kTileW, 0}; + dst[3] = {2.f / 3.f * kM * kTileW, 1 / 2.f * kN * kTileH}; + dst[2] = {1.f / 3.f * kM * kTileW, 1 / 2.f * kN * kTileH - 0.1f * kTileH}; + SkAssertResult(matrices[3].setPolyToPoly(src, dst, 4)); + matrices[3].postTranslate(100.f, d); + SkCanvas::ImageSetEntry set[kM * kN]; + for (int x = 0; x < kM; ++x) { + for (int y = 0; y < kN; ++y) { + set[y * kM + x].fAAFlags = SkCanvas::kNone_QuadAAFlags; + if (x == 0) { + set[y * kM + x].fAAFlags |= SkCanvas::kLeft_QuadAAFlag; + } + if (x == kM - 1) { + set[y * kM + x].fAAFlags |= SkCanvas::kRight_QuadAAFlag; + } + if (y == 0) { + set[y * kM + x].fAAFlags |= SkCanvas::kTop_QuadAAFlag; + } + if (y == kN - 1) { + set[y * kM + x].fAAFlags |= SkCanvas::kBottom_QuadAAFlag; + } + set[y * kM + x].fSrcRect = SkRect::MakeWH(kTileW, kTileH); + set[y * kM + x].fDstRect = SkRect::MakeXYWH(x * kTileW, y * kTileH, kTileW, kTileH); + set[y * kM + x].fImage = fImage[x][y]; + } + } + for (auto fm : {kNone_SkFilterQuality, kLow_SkFilterQuality}) { + for (size_t m = 0; m < SK_ARRAY_COUNT(matrices); ++m) { + // Draw grid of red lines at interior tile boundaries. + static constexpr SkScalar kLineOutset = 10.f; + SkPaint paint; + paint.setAntiAlias(true); + paint.setColor(SK_ColorRED); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(0.f); + for (int x = 1; x < kM; ++x) { + SkPoint pts[] = {{x * kTileW, 0}, {x * kTileW, kN * kTileH}}; + matrices[m].mapPoints(pts, 2); + SkVector v = pts[1] - pts[0]; + v.setLength(v.length() + kLineOutset); + canvas->drawLine(pts[1] - v, pts[0] + v, paint); + } + for (int y = 1; y < kN; ++y) { + SkPoint pts[] = {{0, y * kTileH}, {kTileW * kM, y * kTileH}}; + matrices[m].mapPoints(pts, 2); + SkVector v = pts[1] - pts[0]; + v.setLength(v.length() + kLineOutset); + canvas->drawLine(pts[1] - v, pts[0] + v, paint); + } + canvas->save(); + canvas->concat(matrices[m]); + canvas->experimental_DrawImageSetV0(set, kM * kN, 1.f, fm, SkBlendMode::kSrcOver); + canvas->restore(); + } + // A more exotic case with an unusual blend mode, all aa flags set, and alpha, and + // subsets the image + SkCanvas::ImageSetEntry entry; + entry.fSrcRect = SkRect::MakeWH(kTileW, kTileH).makeInset(kTileW / 4.f, kTileH / 4.f); + entry.fDstRect = SkRect::MakeWH(2 * kTileW, 2 * kTileH).makeOffset(d / 4, 2 * d); + entry.fImage = fImage[0][0]; + entry.fAAFlags = SkCanvas::kAll_QuadAAFlags; + canvas->save(); + canvas->rotate(3.f); + canvas->experimental_DrawImageSetV0(&entry, 1, 0.7f, fm, SkBlendMode::kLuminosity); + canvas->restore(); + canvas->translate(2 * d, 0); + } + } + static constexpr int kM = 4; + static constexpr int kN = 4; + static constexpr SkScalar kTileW = 50; + static constexpr SkScalar kTileH = 50; + sk_sp fImage[kM][kN]; +}; + +DEF_GM(return new DrawImageSetGM();) + +} // namespace skiagm diff --git a/gn/gm.gni b/gn/gm.gni index c8d8928b59..34cc1bfc49 100644 --- a/gn/gm.gni +++ b/gn/gm.gni @@ -10,7 +10,6 @@ gm_sources = [ "$_gm/3dgm.cpp", "$_gm/aaa.cpp", "$_gm/aaclip.cpp", - "$_gm/aaflags.cpp", "$_gm/aarectmodes.cpp", "$_gm/aaxfermodes.cpp", "$_gm/addarc.cpp", @@ -120,6 +119,7 @@ gm_sources = [ "$_gm/drawatlascolor.cpp", "$_gm/drawbitmaprect.cpp", "$_gm/drawlooper.cpp", + "$_gm/drawimageset.cpp", "$_gm/drawminibitmaprect.cpp", "$_gm/drawregion.cpp", "$_gm/drawregionmodes.cpp", diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 11f5372d10..c8132a00b9 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -1820,6 +1820,37 @@ public: void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, const SkPaint* paint = nullptr); + /** + * Controls anti-aliasing of each edge of images in an image-set. + */ + enum QuadAAFlags : unsigned { + kLeft_QuadAAFlag = 0b0001, + kTop_QuadAAFlag = 0b0010, + kRight_QuadAAFlag = 0b0100, + kBottom_QuadAAFlag = 0b1000, + + kNone_QuadAAFlags = 0b0000, + kAll_QuadAAFlags = 0b1111, + }; + + /** This is used by the experimental API below. */ + struct ImageSetEntry { + sk_sp fImage; + SkRect fSrcRect; + SkRect fDstRect; + unsigned fAAFlags; // QuadAAFlags + }; + + /** + * This is an experimental API for the SkiaRenderer Chromium project. The signature will + * surely evolve if this is not removed. It currently offers no performance advantage over + * drawing images independently, though may in the future. The antialiasing flags are intended + * to allow control over each edge's AA status, to allow perfect seaming for tile sets. The + * current implementation only antialiases if all edges are flagged, however. + */ + void experimental_DrawImageSetV0(const ImageSetEntry imageSet[], int cnt, float alpha, + SkFilterQuality quality, SkBlendMode mode); + /** Draws text, with origin at (x, y), using clip, SkMatrix, and SkPaint paint. text meaning depends on SkPaint::TextEncoding; by default, text is encoded as @@ -2446,6 +2477,9 @@ protected: virtual void onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, const SkPaint* paint); + virtual void onDrawImageSet(const ImageSetEntry imageSet[], int count, float alpha, + SkFilterQuality, SkBlendMode); + virtual void onDrawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint); virtual void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, diff --git a/include/core/SkCanvasVirtualEnforcer.h b/include/core/SkCanvasVirtualEnforcer.h index 01765f3218..a6aefa9c30 100644 --- a/include/core/SkCanvasVirtualEnforcer.h +++ b/include/core/SkCanvasVirtualEnforcer.h @@ -58,6 +58,16 @@ protected: void onDrawImageLattice(const SkImage* image, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint* paint) override = 0; +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + // This is under active development for Chrome and not used in Android. Hold off on adding + // implementations in Android's SkCanvas subclasses until this stabilizes. + void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode) override {}; +#else + void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode) override = 0; +#endif + void onDrawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) override = 0; void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, diff --git a/include/core/SkOverdrawCanvas.h b/include/core/SkOverdrawCanvas.h index fc39f386c4..4c2386974a 100644 --- a/include/core/SkOverdrawCanvas.h +++ b/include/core/SkOverdrawCanvas.h @@ -47,6 +47,8 @@ public: SrcRectConstraint) override; void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override; void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override; + void onDrawImageSet(const ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode) override; void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override; void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, SrcRectConstraint) override; diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h index eb77e4ff98..4d8e3c0b89 100644 --- a/include/private/GrTypesPriv.h +++ b/include/private/GrTypesPriv.h @@ -11,6 +11,7 @@ #include #include "GrSharedEnums.h" #include "GrTypes.h" +#include "SkCanvas.h" #include "SkImageInfo.h" #include "SkImageInfoPriv.h" #include "SkRefCnt.h" @@ -287,30 +288,24 @@ enum class GrAllowMixedSamples : bool { kNo = false, kYes = true }; GrAAType GrChooseAAType(GrAA, GrFSAAType, GrAllowMixedSamples, const GrCaps&); -/** - * Controls anti-aliasing of a quad on a per-edge basis. Currently only used by GrTextureOp. - * This will be moved to public API and renamed when this functionality is exposed. - */ -enum class GrQuadAAFlags : unsigned { - kLeft = 0b0001, - kTop = 0b0010, - kRight = 0b0100, - kBottom = 0b1000, +enum class GrQuadAAFlags { + kLeft = SkCanvas::kLeft_QuadAAFlag, + kTop = SkCanvas::kTop_QuadAAFlag, + kRight = SkCanvas::kRight_QuadAAFlag, + kBottom = SkCanvas::kBottom_QuadAAFlag, - kNone = 0b0000, - kAll = 0b1111, - - kTopLeft = kTop | kLeft, - kTopRight = kTop | kRight, - kBottomRight = kBottom | kRight, - kBottomLeft = kBottom | kLeft, + kNone = SkCanvas::kNone_QuadAAFlags, + kAll = SkCanvas::kAll_QuadAAFlags }; GR_MAKE_BITFIELD_CLASS_OPS(GrQuadAAFlags) +static inline GrQuadAAFlags SkToGrQuadAAFlags(unsigned flags) { + return static_cast(flags); +} + /** - * Types of shader-language-specific boxed variables we can create. (Currently only GrGLShaderVars, - * but should be applicable to other shader languages.) + * Types of shader-language-specific boxed variables we can create. */ enum GrSLType { kVoid_GrSLType, diff --git a/include/utils/SkNWayCanvas.h b/include/utils/SkNWayCanvas.h index 998d7b1e6e..a5339d7bdb 100644 --- a/include/utils/SkNWayCanvas.h +++ b/include/utils/SkNWayCanvas.h @@ -63,10 +63,11 @@ protected: const SkPaint*, SrcRectConstraint) override; void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&, const SkPaint*) override; - void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, - const SkPaint*) override; + void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override; void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, const SkPaint*) override; + void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, diff --git a/include/utils/SkNoDrawCanvas.h b/include/utils/SkNoDrawCanvas.h index e0afa0fbe7..350faa1d71 100644 --- a/include/utils/SkNoDrawCanvas.h +++ b/include/utils/SkNoDrawCanvas.h @@ -71,6 +71,8 @@ protected: const SkPaint*) override {} void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override {} + void onDrawImageSet(const SkCanvas::ImageSetEntry[], int, float, SkFilterQuality, + SkBlendMode) override {} void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&, const SkPaint*) override {} void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone[], int, SkBlendMode, diff --git a/include/utils/SkPaintFilterCanvas.h b/include/utils/SkPaintFilterCanvas.h index e6c0c4a588..d83adbfed6 100644 --- a/include/utils/SkPaintFilterCanvas.h +++ b/include/utils/SkPaintFilterCanvas.h @@ -88,6 +88,8 @@ protected: const SkPaint*) override; void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override; + void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode) override; void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, const SkPaint&) override; void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 701a8a1a67..b988b7cf17 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -1796,6 +1796,15 @@ void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, co } } +void SkCanvas::experimental_DrawImageSetV0(const ImageSetEntry imageSet[], int cnt, float alpha, + SkFilterQuality filterQuality, SkBlendMode mode) { + TRACE_EVENT0("skia", TRACE_FUNC); + RETURN_ON_NULL(imageSet); + RETURN_ON_FALSE(cnt); + + this->onDrawImageSet(imageSet, cnt, alpha, filterQuality, mode); +} + void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) { TRACE_EVENT0("skia", TRACE_FUNC); if (bitmap.drawsNothing()) { @@ -2397,6 +2406,16 @@ void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, LOOPER_END } +void SkCanvas::onDrawImageSet(const ImageSetEntry imageSet[], int count, float alpha, + SkFilterQuality filterQuality, SkBlendMode mode) { + SkPaint paint; + LOOPER_BEGIN(paint, nullptr); + while (iter.next()) { + iter.fDevice->drawImageSet(imageSet, count, alpha, filterQuality, mode); + } + LOOPER_END +} + void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst, const SkPaint* paint) { SkPaint realPaint; diff --git a/src/core/SkColorSpaceXformCanvas.cpp b/src/core/SkColorSpaceXformCanvas.cpp index d0702a868b..9ae9cb7e6e 100644 --- a/src/core/SkColorSpaceXformCanvas.cpp +++ b/src/core/SkColorSpaceXformCanvas.cpp @@ -171,6 +171,18 @@ public: dst, MaybePaint(paint, fXformer.get())); } } + void onDrawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha, + SkFilterQuality filterQuality, SkBlendMode mode) override { + SkAutoTArray xformedSet(count); + for (int i = 0; i < count; ++i) { + xformedSet[i].fImage = this->prepareImage(set[i].fImage.get()); + xformedSet[i].fSrcRect = set[i].fSrcRect; + xformedSet[i].fDstRect = set[i].fDstRect; + xformedSet[i].fAAFlags = set[i].fAAFlags; + } + fTarget->experimental_DrawImageSetV0(xformedSet.get(), count, alpha, filterQuality, mode); + } + void onDrawAtlas(const SkImage* atlas, const SkRSXform* xforms, const SkRect* tex, const SkColor* colors, int count, SkBlendMode mode, const SkRect* cull, const SkPaint* paint) override { diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index ba5442eaad..7bf2265c2a 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -202,6 +202,22 @@ void SkBaseDevice::drawImageLattice(const SkImage* image, } } +void SkBaseDevice::drawImageSet(const SkCanvas::ImageSetEntry images[], int count, float alpha, + SkFilterQuality filterQuality, SkBlendMode mode) { + SkPaint paint; + paint.setFilterQuality(SkTPin(filterQuality, kNone_SkFilterQuality, kLow_SkFilterQuality)); + paint.setAlpha(SkToUInt(SkTClamp(SkScalarRoundToInt(alpha * 255), 0, 255))); + paint.setBlendMode(mode); + for (int i = 0; i < count; ++i) { + // TODO: Handle per-edge AA. Right now this mirrors the SkiaRenderer component of Chrome + // which turns off antialiasing unless all four edges should be antialiased. This avoids + // seaming in tiled composited layers. + paint.setAntiAlias(images[i].fAAFlags == SkCanvas::kAll_QuadAAFlags); + this->drawImageRect(images[i].fImage.get(), &images[i].fSrcRect, images[i].fDstRect, paint, + SkCanvas::kFast_SrcRectConstraint); + } +} + void SkBaseDevice::drawBitmapLattice(const SkBitmap& bitmap, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint& paint) { diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h index bfdfffaf2a..e366e79103 100644 --- a/src/core/SkDevice.h +++ b/src/core/SkDevice.h @@ -212,6 +212,8 @@ protected: virtual void drawImageLattice(const SkImage*, const SkCanvas::Lattice&, const SkRect& dst, const SkPaint&); + virtual void drawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, + SkFilterQuality, SkBlendMode); virtual void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, const SkPaint&) = 0; diff --git a/src/core/SkLiteDL.cpp b/src/core/SkLiteDL.cpp index 38db669ffa..ce20896a29 100644 --- a/src/core/SkLiteDL.cpp +++ b/src/core/SkLiteDL.cpp @@ -5,16 +5,17 @@ * found in the LICENSE file. */ +#include "SkLiteDL.h" +#include #include "SkCanvas.h" #include "SkData.h" #include "SkDrawShadowInfo.h" #include "SkImage.h" #include "SkImageFilter.h" -#include "SkLiteDL.h" #include "SkMath.h" #include "SkPicture.h" -#include "SkRegion.h" #include "SkRSXform.h" +#include "SkRegion.h" #include "SkTextBlob.h" #include "SkVertices.h" @@ -46,15 +47,15 @@ static const D* pod(const T* op, size_t offset = 0) { } namespace { -#define TYPES(M) \ - M(Flush) M(Save) M(Restore) M(SaveLayer) \ - M(Concat) M(SetMatrix) M(Translate) \ - M(ClipPath) M(ClipRect) M(ClipRRect) M(ClipRegion) \ - M(DrawPaint) M(DrawPath) M(DrawRect) M(DrawRegion) M(DrawOval) M(DrawArc) \ - M(DrawRRect) M(DrawDRRect) M(DrawAnnotation) M(DrawDrawable) M(DrawPicture) \ - M(DrawImage) M(DrawImageNine) M(DrawImageRect) M(DrawImageLattice) \ - M(DrawText) M(DrawPosText) M(DrawPosTextH) \ - M(DrawTextRSXform) M(DrawTextBlob) \ +#define TYPES(M) \ + M(Flush) M(Save) M(Restore) M(SaveLayer) \ + M(Concat) M(SetMatrix) M(Translate) \ + M(ClipPath) M(ClipRect) M(ClipRRect) M(ClipRegion) \ + M(DrawPaint) M(DrawPath) M(DrawRect) M(DrawRegion) M(DrawOval) M(DrawArc) \ + M(DrawRRect) M(DrawDRRect) M(DrawAnnotation) M(DrawDrawable) M(DrawPicture) \ + M(DrawImage) M(DrawImageNine) M(DrawImageRect) M(DrawImageLattice) M(DrawImageSet) \ + M(DrawText) M(DrawPosText) M(DrawPosTextH) \ + M(DrawTextRSXform) M(DrawTextBlob) \ M(DrawPatch) M(DrawPoints) M(DrawVertices) M(DrawAtlas) M(DrawShadowRec) #define M(T) T, @@ -325,7 +326,22 @@ namespace { &paint); } }; - + struct DrawImageSet final : Op { + static const auto kType = Type::DrawImageSet; + DrawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha, + SkFilterQuality quality, SkBlendMode xfermode) + : count(count), alpha(alpha), quality(quality), xfermode(xfermode), set(count) { + std::copy_n(set, count, this->set.get()); + } + int count; + float alpha; + SkFilterQuality quality; + SkBlendMode xfermode; + SkAutoTArray set; + void draw(SkCanvas* c, const SkMatrix&) const { + c->experimental_DrawImageSetV0(set.get(), count, alpha, quality, xfermode); + } + }; struct DrawText final : Op { static const auto kType = Type::DrawText; DrawText(size_t bytes, SkScalar x, SkScalar y, const SkPaint& paint) @@ -604,6 +620,11 @@ void SkLiteDL::drawImageLattice(sk_sp image, const SkCanvas::Latt lattice.fRectTypes, fs); } +void SkLiteDL::drawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha, + SkFilterQuality filterQuality, SkBlendMode mode) { + this->push(0, set, count, alpha, filterQuality, mode); +} + void SkLiteDL::drawText(const void* text, size_t bytes, SkScalar x, SkScalar y, const SkPaint& paint) { void* pod = this->push(bytes, bytes, x, y, paint); diff --git a/src/core/SkLiteDL.h b/src/core/SkLiteDL.h index 8c40f26778..0a647cc6c7 100644 --- a/src/core/SkLiteDL.h +++ b/src/core/SkLiteDL.h @@ -67,6 +67,8 @@ public: SkCanvas::SrcRectConstraint); void drawImageLattice(sk_sp, const SkCanvas::Lattice&, const SkRect&, const SkPaint*); + void drawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode); void drawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, const SkPaint&); diff --git a/src/core/SkLiteRecorder.cpp b/src/core/SkLiteRecorder.cpp index c9c5cfc9ef..c754859581 100644 --- a/src/core/SkLiteRecorder.cpp +++ b/src/core/SkLiteRecorder.cpp @@ -159,6 +159,10 @@ void SkLiteRecorder::onDrawImageLattice(const SkImage* img, fDL->drawImageLattice(sk_ref_sp(img), lattice, dst, paint); } +void SkLiteRecorder::onDrawImageSet(const ImageSetEntry set[], int count, float alpha, + SkFilterQuality filterQuality, SkBlendMode mode) { + fDL->drawImageSet(set, count, alpha, filterQuality, mode); +} void SkLiteRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], diff --git a/src/core/SkLiteRecorder.h b/src/core/SkLiteRecorder.h index 42c95a6cc4..181ed86ca8 100644 --- a/src/core/SkLiteRecorder.h +++ b/src/core/SkLiteRecorder.h @@ -67,6 +67,8 @@ public: void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override; void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*, SrcRectConstraint) override; + void onDrawImageSet(const ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode) override; void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, const SkPaint&) override; diff --git a/src/core/SkOverdrawCanvas.cpp b/src/core/SkOverdrawCanvas.cpp index 1e256fa08b..29d30b6b0f 100644 --- a/src/core/SkOverdrawCanvas.cpp +++ b/src/core/SkOverdrawCanvas.cpp @@ -272,6 +272,13 @@ void SkOverdrawCanvas::onDrawImageLattice(const SkImage* image, const Lattice& l } } +void SkOverdrawCanvas::onDrawImageSet(const ImageSetEntry set[], int count, float alpha, + SkFilterQuality, SkBlendMode) { + for (int i = 0; i < count; ++i) { + fList[0]->onDrawRect(set[i].fDstRect, fPaint); + } +} + void SkOverdrawCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint*) { fList[0]->onDrawRect(SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()), fPaint); diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h index 253438a5fc..b461dccfc5 100644 --- a/src/core/SkPictureFlat.h +++ b/src/core/SkPictureFlat.h @@ -97,7 +97,8 @@ enum DrawType { FLUSH, - LAST_DRAWTYPE_ENUM = FLUSH + DRAW_IMAGE_SET, + LAST_DRAWTYPE_ENUM = DRAW_IMAGE_SET }; enum DrawVertexFlags { diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index 1ba85ff8d8..6462698020 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -355,6 +355,22 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, canvas->legacy_drawImageRect(image, src, dst, paint, constraint); } break; + case DRAW_IMAGE_SET: { + int cnt = reader->readInt(); + float alpha = SkScalarToFloat(reader->readScalar()); + SkFilterQuality filterQuality = (SkFilterQuality)reader->readUInt(); + SkBlendMode mode = (SkBlendMode)reader->readUInt(); + SkAutoTArray set(cnt); + for (int i = 0; i < cnt; ++i) { + set[i].fImage = sk_ref_sp(fPictureData->getImage(reader)); + reader->readRect(&set[i].fSrcRect); + reader->readRect(&set[i].fDstRect); + set[i].fAAFlags = reader->readUInt(); + } + BREAK_ON_READ_ERROR(reader); + + canvas->experimental_DrawImageSetV0(set.get(), cnt, alpha, filterQuality, mode); + } break; case DRAW_OVAL: { const SkPaint* paint = fPictureData->getPaint(reader); SkRect rect; diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index 56a01357a1..702631f9a1 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -543,6 +543,25 @@ void SkPictureRecord::onDrawImageLattice(const SkImage* image, const Lattice& la this->validate(initialOffset, size); } +void SkPictureRecord::onDrawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha, + SkFilterQuality filterQuality, SkBlendMode mode) { + // op + count + alpha + fq + mode + (image index, src rect, dst rect, aa flags) * cnt + size_t size = + 4 * kUInt32Size + sizeof(SkScalar) + (2 * kUInt32Size + 2 * sizeof(SkRect)) * count; + size_t initialOffset = this->addDraw(DRAW_IMAGE_SET, &size); + this->addInt(count); + this->addScalar(SkFloatToScalar(alpha)); + this->addInt((int)filterQuality); + this->addInt((int)mode); + for (int i = 0; i < count; ++i) { + this->addImage(set[i].fImage.get()); + this->addRect(set[i].fSrcRect); + this->addRect(set[i].fDstRect); + this->addInt((int)set[i].fAAFlags); + } + this->validate(initialOffset, size); +} + void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { // op + paint index + length + 'length' worth of chars + x + y diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h index 206483d9de..8cb0974605 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -193,6 +193,8 @@ protected: const SkPaint*) override; void onDrawImageLattice(const SkImage*, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint*) override; + void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode) override; void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, const SkPaint&) override; diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp index 26df05a149..6b19202c60 100644 --- a/src/core/SkRecordDraw.cpp +++ b/src/core/SkRecordDraw.cpp @@ -109,6 +109,7 @@ template <> void Draw::draw(const DrawImageLattice& r) { DRAW(DrawImageRect, legacy_drawImageRect(r.image.get(), r.src, r.dst, r.paint, r.constraint)); DRAW(DrawImageNine, drawImageNine(r.image.get(), r.center, r.dst, r.paint)); +DRAW(DrawImageSet, experimental_DrawImageSetV0(r.set.get(), r.count, r.alpha, r.quality, r.mode)); DRAW(DrawOval, drawOval(r.oval, r.paint)); DRAW(DrawPaint, drawPaint(r.paint)); DRAW(DrawPath, drawPath(r.path, r.paint)); @@ -383,6 +384,13 @@ private: Bounds bounds(const DrawImageNine& op) const { return this->adjustAndMap(op.dst, op.paint); } + Bounds bounds(const DrawImageSet& op) const { + SkRect rect = SkRect::MakeEmpty(); + for (int i = 0; i < op.count; ++i) { + rect.join(this->adjustAndMap(op.set[i].fDstRect, nullptr)); + } + return rect; + } Bounds bounds(const DrawPath& op) const { return op.path.isInverseFillType() ? fCullRect : this->adjustAndMap(op.path.getBounds(), &op.paint); diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp index f7f35c593c..daefd8e8bd 100644 --- a/src/core/SkRecorder.cpp +++ b/src/core/SkRecorder.cpp @@ -253,6 +253,15 @@ void SkRecorder::onDrawImageLattice(const SkImage* image, const Lattice& lattice this->copy(lattice.fColors, flagCount), *lattice.fBounds, dst); } +void SkRecorder::onDrawImageSet(const ImageSetEntry set[], int count, float alpha, + SkFilterQuality filterQuality, SkBlendMode mode) { + SkAutoTArray setCopy(count); + for (int i = 0; i < count; ++i) { + setCopy[i] = set[i]; + } + this->append(std::move(setCopy), count, alpha, filterQuality, mode); +} + void SkRecorder::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { this->append( diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h index 3035dba4c2..c60d4fd0a6 100644 --- a/src/core/SkRecorder.h +++ b/src/core/SkRecorder.h @@ -116,6 +116,8 @@ public: const SkPaint*) override; void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, const SkRect& dst, const SkPaint*) override; + void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode) override; void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, const SkPaint&) override; void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h index 4a1698336d..3961e0505a 100644 --- a/src/core/SkRecords.h +++ b/src/core/SkRecords.h @@ -64,6 +64,7 @@ namespace SkRecords { M(DrawImageLattice) \ M(DrawImageRect) \ M(DrawImageNine) \ + M(DrawImageSet) \ M(DrawDRRect) \ M(DrawOval) \ M(DrawPaint) \ @@ -265,6 +266,12 @@ RECORD(DrawImageNine, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, sk_sp image; SkIRect center; SkRect dst); +RECORD(DrawImageSet, kDraw_Tag|kHasImage_Tag, + SkAutoTArray set; + int count; + float alpha; + SkFilterQuality quality; + SkBlendMode mode); RECORD(DrawOval, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRect oval); diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index 2fbf7db57e..584ed3340d 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -798,6 +798,21 @@ void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_spaddDrawOp(clip, std::move(op)); } +void GrRenderTargetContext::drawTextureSet(const GrClip& clip, const TextureSetEntry set[], int cnt, + GrSamplerState::Filter filter, GrColor color, + const SkMatrix& viewMatrix, + sk_sp texXform, + sk_sp colorXform) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureSet", fContext); + GrAAType aaType = this->chooseAAType(GrAA::kYes, GrAllowMixedSamples::kNo); + auto op = GrTextureOp::Make(fContext, set, cnt, filter, color, aaType, viewMatrix, + std::move(texXform), std::move(colorXform)); + this->addDrawOp(clip, std::move(op)); +} + void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip, GrPaint&& paint, GrAA aa, diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h index 7858eeea22..c4a6740a7c 100644 --- a/src/gpu/GrRenderTargetContext.h +++ b/src/gpu/GrRenderTargetContext.h @@ -139,6 +139,21 @@ public: SkCanvas::SrcRectConstraint, const SkMatrix& viewMatrix, sk_sp texXform, sk_sp colorXform); + /** Used with drawTextureSet */ + struct TextureSetEntry { + sk_sp fProxy; + SkRect fSrcRect; + SkRect fDstRect; + GrQuadAAFlags fAAFlags; + }; + /** + * Draws a set of textures with a shared filter, color, view matrix, color xform, and + * texture color xform. The textures must all have the same GrTextureType and GrConfig. + */ + void drawTextureSet(const GrClip&, const TextureSetEntry[], int cnt, GrSamplerState::Filter, + GrColor, const SkMatrix& viewMatrix, sk_sp texXform, + sk_sp colorXform); + /** * Draw a roundrect using a paint. * diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 6239477e52..5e8cfcad98 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1446,6 +1446,62 @@ void SkGpuDevice::drawBitmapLattice(const SkBitmap& bitmap, this->drawProducerLattice(&maker, std::move(iter), dst, paint); } +void SkGpuDevice::drawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha, + SkFilterQuality filterQuality, SkBlendMode mode) { + SkASSERT(count > 0); + if (mode != SkBlendMode::kSrcOver || + !fContext->contextPriv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) { + INHERITED::drawImageSet(set, count, alpha, filterQuality, mode); + return; + } + GrSamplerState sampler; + sampler.setFilterMode(kNone_SkFilterQuality == filterQuality ? GrSamplerState::Filter::kNearest + : GrSamplerState::Filter::kBilerp); + SkAutoTArray textures(count); + GrColor color = GrColorPackA4(SkToUInt(SkTClamp(SkScalarRoundToInt(alpha * 255), 0, 255))); + // We accumulate compatible proxies until we find an an incompatible one or reach the end and + // issue the accumulated 'n' draws starting at 'base'. + int base = 0, n = 0; + auto draw = [&] { + if (n > 0) { + auto textureXform = GrColorSpaceXform::Make( + set[base].fImage->colorSpace(), set[base].fImage->alphaType(), + fRenderTargetContext->colorSpaceInfo().colorSpace(), kPremul_SkAlphaType); + fRenderTargetContext->drawTextureSet(this->clip(), textures.get() + base, n, + sampler.filter(), color, this->ctm(), + std::move(textureXform), nullptr); + } + }; + for (int i = 0; i < count; ++i) { + textures[i].fProxy = + as_IB(set[i].fImage.get()) + ->asTextureProxyRef(fContext.get(), GrSamplerState::ClampBilerp(), nullptr, + nullptr, nullptr); + textures[i].fSrcRect = set[i].fSrcRect; + textures[i].fDstRect = set[i].fDstRect; + textures[i].fAAFlags = SkToGrQuadAAFlags(set[i].fAAFlags); + // If we failed to make a proxy or our proxy can't be grouped with the previous proxies then + // draw the accumulated set and reset. + if (!textures[i].fProxy) { + draw(); + base = i + 1; + n = 0; + } else if (n > 0 && + (textures[i].fProxy->textureType() != textures[base].fProxy->textureType() || + textures[i].fProxy->config() != textures[base].fProxy->config() || + set[i].fImage->alphaType() != set[base].fImage->alphaType() || + !SkColorSpace::Equals(set[i].fImage->colorSpace(), + set[base].fImage->colorSpace()))) { + draw(); + base = i; + n = 1; + } else { + ++n; + } + } + draw(); +} + static bool init_vertices_paint(GrContext* context, const GrColorSpaceInfo& colorSpaceInfo, const SkPaint& skPaint, const SkMatrix& matrix, SkBlendMode bmode, bool hasTexs, bool hasColors, GrPaint* grPaint) { diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h index c0dec2903b..81d4f11ae9 100644 --- a/src/gpu/SkGpuDevice.h +++ b/src/gpu/SkGpuDevice.h @@ -105,6 +105,8 @@ public: const SkRect& dst, const SkPaint&) override; void drawBitmapLattice(const SkBitmap&, const SkCanvas::Lattice&, const SkRect& dst, const SkPaint&) override; + void drawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode) override; void drawSpecial(SkSpecialImage*, int left, int top, const SkPaint& paint, SkImage*, const SkMatrix&) override; diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp index 4f49cea272..ee1af7c6f1 100644 --- a/src/gpu/ops/GrTextureOp.cpp +++ b/src/gpu/ops/GrTextureOp.cpp @@ -6,7 +6,7 @@ */ #include "GrTextureOp.h" - +#include #include "GrAppliedClip.h" #include "GrCaps.h" #include "GrContext.h" @@ -27,13 +27,13 @@ #include "SkMatrixPriv.h" #include "SkPoint.h" #include "SkPoint3.h" +#include "SkRectPriv.h" #include "SkTo.h" #include "glsl/GrGLSLColorSpaceXformHelper.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLVarying.h" #include "glsl/GrGLSLVertexGeoBuilder.h" -#include namespace { @@ -271,8 +271,6 @@ private: // output. static void compute_quad_edges_and_outset_vertices(GrQuadAAFlags aaFlags, Sk4f* x, Sk4f* y, Sk4f* a, Sk4f* b, Sk4f* c, bool outsetCorners) { - SkASSERT(GrQuadAAFlags::kNone != aaFlags); - static constexpr auto fma = SkNx_fma<4, float>; // These rotate the points/edge values either clockwise or counterclockwise assuming tri strip // order. @@ -594,34 +592,56 @@ public: std::move(proxy), filter, color, srcRect, dstRect, aaType, aaFlags, constraint, viewMatrix, std::move(textureColorSpaceXform), std::move(paintColorSpaceXform)); } + static std::unique_ptr Make(GrContext* context, + const GrRenderTargetContext::TextureSetEntry set[], + int cnt, GrSamplerState::Filter filter, GrColor color, + GrAAType aaType, const SkMatrix& viewMatrix, + sk_sp textureColorSpaceXform, + sk_sp paintColorSpaceXform) { + size_t size = sizeof(TextureOp) + sizeof(Proxy) * (cnt - 1); + GrOpMemoryPool* pool = context->contextPriv().opMemoryPool(); + void* mem = pool->allocate(size); + return std::unique_ptr(new (mem) TextureOp( + set, cnt, filter, color, aaType, viewMatrix, std::move(textureColorSpaceXform), + std::move(paintColorSpaceXform))); + } ~TextureOp() override { - if (fFinalized) { - fProxy->completedRead(); - } else { - fProxy->unref(); + for (unsigned p = 0; p < fProxyCnt; ++p) { + if (fFinalized) { + fProxies[p].fProxy->completedRead(); + } else { + fProxies[p].fProxy->unref(); + } } } const char* name() const override { return "TextureOp"; } - void visitProxies(const VisitProxyFunc& func) const override { func(fProxy); } + void visitProxies(const VisitProxyFunc& func) const override { + for (unsigned p = 0; p < fProxyCnt; ++p) { + func(fProxies[p].fProxy); + } + } SkString dumpInfo() const override { SkString str; - str.appendf("# draws: %d\n", fDraws.count()); - str.appendf("Proxy ID: %d, Filter: %d\n", fProxy->uniqueID().asUInt(), - static_cast(fFilter)); - for (int i = 0; i < fDraws.count(); ++i) { - const Draw& draw = fDraws[i]; - str.appendf( - "%d: Color: 0x%08x, TexRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f] " - "Quad [(%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f)]\n", - i, draw.color(), draw.srcRect().fLeft, draw.srcRect().fTop, - draw.srcRect().fRight, draw.srcRect().fBottom, draw.quad().point(0).fX, - draw.quad().point(0).fY, draw.quad().point(1).fX, draw.quad().point(1).fY, - draw.quad().point(2).fX, draw.quad().point(2).fY, draw.quad().point(3).fX, - draw.quad().point(3).fY); + str.appendf("# draws: %d\n", fQuads.count()); + int q = 0; + for (unsigned p = 0; p < fProxyCnt; ++p) { + str.appendf("Proxy ID: %d, Filter: %d\n", fProxies[p].fProxy->uniqueID().asUInt(), + static_cast(fFilter)); + for (int i = 0; i < fProxies[p].fQuadCnt; ++i, ++q) { + const Quad& quad = fQuads[q]; + str.appendf( + "%d: Color: 0x%08x, TexRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f] " + "Quad [(%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f)]\n", + i, quad.color(), quad.srcRect().fLeft, quad.srcRect().fTop, + quad.srcRect().fRight, quad.srcRect().fBottom, quad.quad().point(0).fX, + quad.quad().point(0).fY, quad.quad().point(1).fX, quad.quad().point(1).fY, + quad.quad().point(2).fX, quad.quad().point(2).fY, quad.quad().point(3).fX, + quad.quad().point(3).fY); + } } str += INHERITED::dumpInfo(); return str; @@ -630,8 +650,10 @@ public: RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override { SkASSERT(!fFinalized); fFinalized = true; - fProxy->addPendingRead(); - fProxy->unref(); + for (unsigned p = 0; p < fProxyCnt; ++p) { + fProxies[p].fProxy->addPendingRead(); + fProxies[p].fProxy->unref(); + } return RequiresDstTexture::kNo; } @@ -653,7 +675,6 @@ private: : INHERITED(ClassID()) , fTextureColorSpaceXform(std::move(textureColorSpaceXform)) , fPaintColorSpaceXform(std::move(paintColorSpaceXform)) - , fProxy(proxy.release()) , fFilter(filter) , fAAType(static_cast(aaType)) , fFinalized(0) { @@ -673,11 +694,11 @@ private: SK_ABORT("Should not use mixed sample AA"); break; } - fPerspective = viewMatrix.hasPerspective(); + fPerspective = static_cast(viewMatrix.hasPerspective()); auto quad = GrPerspQuad(dstRect, viewMatrix); auto bounds = quad.bounds(); // We expect our caller to have already caught this optimization. - SkASSERT(!srcRect.contains(fProxy->getWorstCaseBoundsRect()) || + SkASSERT(!srcRect.contains(proxy->getWorstCaseBoundsRect()) || constraint == SkCanvas::kFast_SrcRectConstraint); if (viewMatrix.rectStaysRect()) { // Disable filtering when there is no scaling or fractional translation. @@ -707,48 +728,107 @@ private: this->aaType() != GrAAType::kCoverage) { constraint = SkCanvas::kFast_SrcRectConstraint; } - const auto& draw = fDraws.emplace_back(srcRect, quad, aaFlags, constraint, color); - this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); - fDomain = static_cast(draw.domain()); + const auto& draw = fQuads.emplace_back(srcRect, quad, aaFlags, constraint, color); + fProxyCnt = 1; + fProxies[0] = {proxy.release(), 1}; + this->setBounds(bounds, HasAABloat(this->aaType() == GrAAType::kCoverage), IsZeroArea::kNo); + fDomain = static_cast(draw.domain()); + } + TextureOp(const GrRenderTargetContext::TextureSetEntry set[], int cnt, + GrSamplerState::Filter filter, GrColor color, GrAAType aaType, + const SkMatrix& viewMatrix, sk_sp textureColorSpaceXform, + sk_sp paintColorSpaceXform) + : INHERITED(ClassID()) + , fTextureColorSpaceXform(std::move(textureColorSpaceXform)) + , fPaintColorSpaceXform(std::move(paintColorSpaceXform)) + , fFilter(filter) + , fAAType(static_cast(aaType)) + , fFinalized(0) { + fQuads.reserve(cnt); + fProxyCnt = SkToUInt(cnt); + SkRect bounds = SkRectPriv::MakeLargestInverted(); + bool aa = false; + for (unsigned p = 0; p < fProxyCnt; ++p) { + fProxies[p].fProxy = SkRef(set[p].fProxy.get()); + fProxies[p].fQuadCnt = 1; + SkASSERT(fProxies[p].fProxy->textureType() == fProxies[0].fProxy->textureType()); + SkASSERT(fProxies[p].fProxy->config() == fProxies[0].fProxy->config()); + auto quad = GrPerspQuad(set[p].fDstRect, viewMatrix); + bounds.joinPossiblyEmptyRect(quad.bounds()); + GrQuadAAFlags aaFlags = set[p].fAAFlags; + switch (aaType) { + case GrAAType::kNone: + aaFlags = GrQuadAAFlags::kNone; + break; + case GrAAType::kCoverage: + break; + case GrAAType::kMSAA: + aaFlags = GrQuadAAFlags::kAll; + break; + case GrAAType::kMixedSamples: + SK_ABORT("Should not use mixed sample AA"); + break; + } + aa = aa || (set[p].fAAFlags != GrQuadAAFlags::kNone); + fQuads.emplace_back(set[p].fSrcRect, quad, aaFlags, SkCanvas::kFast_SrcRectConstraint, + color); + } + if (!aa) { + fAAType = static_cast(GrAAType::kNone); + } + this->setBounds(bounds, HasAABloat(this->aaType() == GrAAType::kCoverage), IsZeroArea::kNo); + fPerspective = static_cast(viewMatrix.hasPerspective()); + fDomain = static_cast(false); } template - void tess(void* v, const GrGeometryProcessor* gp) const { + void tess(void* v, const GrGeometryProcessor* gp, const GrTextureProxy* proxy, int start, + int cnt) const { + TRACE_EVENT0("skia", TRACE_FUNC); using Vertex = TextureGeometryProcessor::Vertex; SkASSERT(gp->debugOnly_vertexStride() == sizeof(Vertex)); auto vertices = static_cast(v); - auto origin = fProxy->origin(); - const auto* texture = fProxy->peekTexture(); + auto origin = proxy->origin(); + const auto* texture = proxy->peekTexture(); float iw = 1.f / texture->width(); float ih = 1.f / texture->height(); - for (const auto& draw : fDraws) { - tessellate_quad(draw.quad(), draw.aaFlags(), draw.srcRect(), draw.color(), - origin, fFilter, vertices, iw, ih, draw.domain()); + for (int i = start; i < start + cnt; ++i) { + const auto q = fQuads[i]; + tessellate_quad(q.quad(), q.aaFlags(), q.srcRect(), q.color(), origin, fFilter, + vertices, iw, ih, q.domain()); vertices += 4; } } void onPrepareDraws(Target* target) override { + TRACE_EVENT0("skia", TRACE_FUNC); bool hasPerspective = false; Domain domain = Domain::kNo; - int numOps = 0; + int numProxies = 0; + auto textureType = fProxies[0].fProxy->textureType(); + auto config = fProxies[0].fProxy->config(); for (const auto& op : ChainRange(this)) { - ++numOps; hasPerspective |= op.fPerspective; if (op.fDomain) { domain = Domain::kYes; } - if (!op.fProxy->instantiate(target->resourceProvider())) { - return; + numProxies += op.fProxyCnt; + for (unsigned p = 0; p < op.fProxyCnt; ++p) { + auto* proxy = op.fProxies[p].fProxy; + if (!proxy->instantiate(target->resourceProvider())) { + return; + } + SkASSERT(proxy->config() == config); + SkASSERT(proxy->textureType() == textureType); } } bool coverageAA = GrAAType::kCoverage == this->aaType(); sk_sp gp = TextureGeometryProcessor::Make( - fProxy->textureType(), fProxy->config(), fFilter, - std::move(fTextureColorSpaceXform), std::move(fPaintColorSpaceXform), coverageAA, - hasPerspective, domain, *target->caps().shaderCaps()); + textureType, config, fFilter, std::move(fTextureColorSpaceXform), + std::move(fPaintColorSpaceXform), coverageAA, hasPerspective, domain, + *target->caps().shaderCaps()); GrPipeline::InitArgs args; args.fProxy = target->proxy(); args.fCaps = &target->caps(); @@ -763,12 +843,12 @@ private: // Otherwise, we use fixed dynamic state to specify the single op's proxy. GrPipeline::DynamicStateArrays* dynamicStateArrays = nullptr; GrPipeline::FixedDynamicState* fixedDynamicState; - if (numOps > 1) { - dynamicStateArrays = target->allocDynamicStateArrays(numOps, 1, false); + if (numProxies > 1) { + dynamicStateArrays = target->allocDynamicStateArrays(numProxies, 1, false); fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect(), 0); } else { fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect(), 1); - fixedDynamicState->fPrimitiveProcessorTextures[0] = fProxy; + fixedDynamicState->fPrimitiveProcessorTextures[0] = fProxies[0].fProxy; } const auto* pipeline = target->allocPipeline(args, GrProcessorSet::MakeEmptySet(), std::move(clip)); @@ -799,44 +879,53 @@ private: SkASSERT(kTessFnsAndVertexSizes[tessFnIdx].fVertexSize == gp->debugOnly_vertexStride()); - GrMesh* meshes = target->allocMeshes(numOps); - int i = 0; + GrMesh* meshes = target->allocMeshes(numProxies); + int m = 0; for (const auto& op : ChainRange(this)) { - int vstart; - const GrBuffer* vbuffer; - void* vdata = target->makeVertexSpace(kTessFnsAndVertexSizes[tessFnIdx].fVertexSize, - 4 * op.fDraws.count(), &vbuffer, &vstart); - if (!vdata) { - SkDebugf("Could not allocate vertices\n"); - return; - } - - (op.*(kTessFnsAndVertexSizes[tessFnIdx].fTessFn))(vdata, gp.get()); - - if (op.fDraws.count() > 1) { - meshes[i].setPrimitiveType(GrPrimitiveType::kTriangles); - sk_sp ibuffer = target->resourceProvider()->refQuadIndexBuffer(); - if (!ibuffer) { - SkDebugf("Could not allocate quad indices\n"); + int q = 0; + for (unsigned p = 0; p < op.fProxyCnt; ++p) { + int quadCnt = op.fProxies[p].fQuadCnt; + auto* proxy = op.fProxies[p].fProxy; + int vstart; + const GrBuffer* vbuffer; + void* vdata = target->makeVertexSpace(kTessFnsAndVertexSizes[tessFnIdx].fVertexSize, + 4 * quadCnt, &vbuffer, &vstart); + if (!vdata) { + SkDebugf("Could not allocate vertices\n"); return; } - meshes[i].setIndexedPatterned(ibuffer.get(), 6, 4, op.fDraws.count(), - GrResourceProvider::QuadCountOfQuadBuffer()); - } else { - meshes[i].setPrimitiveType(GrPrimitiveType::kTriangleStrip); - meshes[i].setNonIndexedNonInstanced(4); + + (op.*(kTessFnsAndVertexSizes[tessFnIdx].fTessFn))(vdata, gp.get(), proxy, q, + quadCnt); + + if (quadCnt > 1) { + meshes[m].setPrimitiveType(GrPrimitiveType::kTriangles); + sk_sp ibuffer = + target->resourceProvider()->refQuadIndexBuffer(); + if (!ibuffer) { + SkDebugf("Could not allocate quad indices\n"); + return; + } + meshes[m].setIndexedPatterned(ibuffer.get(), 6, 4, quadCnt, + GrResourceProvider::QuadCountOfQuadBuffer()); + } else { + meshes[m].setPrimitiveType(GrPrimitiveType::kTriangleStrip); + meshes[m].setNonIndexedNonInstanced(4); + } + meshes[m].setVertexData(vbuffer, vstart); + if (dynamicStateArrays) { + dynamicStateArrays->fPrimitiveProcessorTextures[m] = proxy; + } + ++m; + q += quadCnt; } - meshes[i].setVertexData(vbuffer, vstart); - if (dynamicStateArrays) { - dynamicStateArrays->fPrimitiveProcessorTextures[i] = op.fProxy; - } - ++i; } target->draw(std::move(gp), pipeline, fixedDynamicState, dynamicStateArrays, meshes, - numOps); + numProxies); } CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + TRACE_EVENT0("skia", TRACE_FUNC); const auto* that = t->cast(); if (!GrColorSpaceXform::Equals(fTextureColorSpaceXform.get(), that->fTextureColorSpaceXform.get())) { @@ -854,17 +943,21 @@ private: if (fFilter != that->fFilter) { return CombineResult::kCannotCombine; } - if (fProxy->uniqueID() != that->fProxy->uniqueID() || that->isChained()) { + auto thisProxy = fProxies[0].fProxy; + auto thatProxy = that->fProxies[0].fProxy; + if (fProxyCnt > 1 || that->fProxyCnt > 1 || + thisProxy->uniqueID() != thatProxy->uniqueID() || that->isChained()) { // We can't merge across different proxies (and we're disallowed from merging when // 'that' is chained. Check if we can be chained with 'that'. - if (fProxy->config() == that->fProxy->config() && - fProxy->textureType() == that->fProxy->textureType() && + if (thisProxy->config() == thatProxy->config() && + thisProxy->textureType() == thatProxy->textureType() && caps.dynamicStateArrayGeometryProcessorTextureSupport()) { return CombineResult::kMayChain; } return CombineResult::kCannotCombine; } - fDraws.push_back_n(that->fDraws.count(), that->fDraws.begin()); + fProxies[0].fQuadCnt += that->fQuads.count(); + fQuads.push_back_n(that->fQuads.count(), that->fQuads.begin()); this->joinBounds(*that); fPerspective |= that->fPerspective; fDomain |= that->fDomain; @@ -873,9 +966,9 @@ private: GrAAType aaType() const { return static_cast(fAAType); } - class Draw { + class Quad { public: - Draw(const SkRect& srcRect, const GrPerspQuad& quad, GrQuadAAFlags aaFlags, + Quad(const SkRect& srcRect, const GrPerspQuad& quad, GrQuadAAFlags aaFlags, SkCanvas::SrcRectConstraint constraint, GrColor color) : fSrcRect(srcRect) , fQuad(quad) @@ -897,16 +990,21 @@ private: unsigned fHasDomain : 1; unsigned fAAFlags : 4; }; - SkSTArray<1, Draw, true> fDraws; + struct Proxy { + GrTextureProxy* fProxy; + int fQuadCnt; + }; + SkSTArray<1, Quad, true> fQuads; sk_sp fTextureColorSpaceXform; sk_sp fPaintColorSpaceXform; - GrTextureProxy* fProxy; GrSamplerState::Filter fFilter; unsigned fAAType : 2; unsigned fPerspective : 1; unsigned fDomain : 1; // Used to track whether fProxy is ref'ed or has a pending IO after finalize() is called. unsigned fFinalized : 1; + unsigned fProxyCnt : 32 - 5; + Proxy fProxies[1]; typedef GrMeshDrawOp INHERITED; }; @@ -932,6 +1030,19 @@ std::unique_ptr Make(GrContext* context, std::move(paintColorSpaceXform)); } +std::unique_ptr Make(GrContext* context, + const GrRenderTargetContext::TextureSetEntry set[], + int cnt, + GrSamplerState::Filter filter, + GrColor color, + GrAAType aaType, + const SkMatrix& viewMatrix, + sk_sp textureColorSpaceXform, + sk_sp paintColorSpaceXform) { + return TextureOp::Make(context, set, cnt, filter, color, aaType, viewMatrix, + std::move(textureColorSpaceXform), std::move(paintColorSpaceXform)); +} + } // namespace GrTextureOp #if GR_TEST_UTILS diff --git a/src/gpu/ops/GrTextureOp.h b/src/gpu/ops/GrTextureOp.h index 992a0331f1..2cf263b9c1 100644 --- a/src/gpu/ops/GrTextureOp.h +++ b/src/gpu/ops/GrTextureOp.h @@ -6,6 +6,7 @@ */ #include "GrColor.h" +#include "GrRenderTargetContext.h" #include "GrSamplerState.h" #include "GrTypesPriv.h" #include "SkCanvas.h" @@ -38,4 +39,14 @@ std::unique_ptr Make(GrContext*, const SkMatrix& viewMatrix, sk_sp textureXform, sk_sp paintXform); + +std::unique_ptr Make(GrContext*, + const GrRenderTargetContext::TextureSetEntry[], + int cnt, + GrSamplerState::Filter, + GrColor, + GrAAType, + const SkMatrix& viewMatrix, + sk_sp textureXform, + sk_sp paintXform); } diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp index 660fcd0c47..4a80915234 100644 --- a/src/utils/SkNWayCanvas.cpp +++ b/src/utils/SkNWayCanvas.cpp @@ -257,6 +257,14 @@ void SkNWayCanvas::onDrawImageLattice(const SkImage* image, const Lattice& latti } } +void SkNWayCanvas::onDrawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha, + SkFilterQuality filterQuality, SkBlendMode mode) { + Iter iter(fList); + while (iter.next()) { + iter->experimental_DrawImageSetV0(set, count, alpha, filterQuality, mode); + } +} + void SkNWayCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { Iter iter(fList); diff --git a/src/utils/SkPaintFilterCanvas.cpp b/src/utils/SkPaintFilterCanvas.cpp index 6000b1ed1d..1ec52934ae 100644 --- a/src/utils/SkPaintFilterCanvas.cpp +++ b/src/utils/SkPaintFilterCanvas.cpp @@ -173,6 +173,18 @@ void SkPaintFilterCanvas::onDrawImageLattice(const SkImage* image, const Lattice } } +void SkPaintFilterCanvas::onDrawImageSet(const SkCanvas::ImageSetEntry set[], int count, + float alpha, SkFilterQuality filterQuality, + SkBlendMode mode) { + SkPaint paint; + paint.setBlendMode(mode); + AutoPaintFilter apf(this, kBitmap_Type, &paint); + mode = paint.getBlendMode(); + if (apf.shouldDraw()) { + this->SkNWayCanvas::onDrawImageSet(set, count, alpha, filterQuality, mode); + } +} + void SkPaintFilterCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount, SkBlendMode bmode, const SkPaint& paint) { diff --git a/tools/debugger/SkDebugCanvas.cpp b/tools/debugger/SkDebugCanvas.cpp index 457dbbf20d..7dabbd3798 100644 --- a/tools/debugger/SkDebugCanvas.cpp +++ b/tools/debugger/SkDebugCanvas.cpp @@ -357,6 +357,11 @@ void SkDebugCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, this->addDrawCommand(new SkDrawImageNineCommand(image, center, dst, paint)); } +void SkDebugCanvas::onDrawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha, + SkFilterQuality filterQuality, SkBlendMode mode) { + this->addDrawCommand(new SkDrawImageSetCommand(set, count, alpha, filterQuality, mode)); +} + void SkDebugCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) { this->addDrawCommand(new SkDrawOvalCommand(oval, paint)); } diff --git a/tools/debugger/SkDebugCanvas.h b/tools/debugger/SkDebugCanvas.h index 437aa974cd..2d5c80095f 100644 --- a/tools/debugger/SkDebugCanvas.h +++ b/tools/debugger/SkDebugCanvas.h @@ -158,6 +158,8 @@ protected: const SkRect& dst, const SkPaint* paint) override; void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, const SkPaint*, SrcRectConstraint) override; + void onDrawImageSet(const ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode) override; void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, diff --git a/tools/debugger/SkDrawCommand.cpp b/tools/debugger/SkDrawCommand.cpp index 27b34efba7..6bdba388d8 100644 --- a/tools/debugger/SkDrawCommand.cpp +++ b/tools/debugger/SkDrawCommand.cpp @@ -7,12 +7,15 @@ #include "SkDrawCommand.h" +#include #include "SkAutoMalloc.h" +#include "SkClipOpPriv.h" #include "SkColorFilter.h" #include "SkDashPathEffect.h" #include "SkDrawable.h" #include "SkImageFilter.h" #include "SkJsonWriteBuffer.h" +#include "SkLatticeIter.h" #include "SkMaskFilterBase.h" #include "SkPaintDefaults.h" #include "SkPathEffect.h" @@ -20,13 +23,11 @@ #include "SkPngEncoder.h" #include "SkReadBuffer.h" #include "SkRectPriv.h" -#include "SkTextBlobPriv.h" +#include "SkShadowFlags.h" #include "SkTHash.h" +#include "SkTextBlobPriv.h" #include "SkTypeface.h" #include "SkWriteBuffer.h" -#include "SkClipOpPriv.h" -#include -#include #define SKDEBUGCANVAS_ATTRIBUTE_COMMAND "command" #define SKDEBUGCANVAS_ATTRIBUTE_VISIBLE "visible" @@ -227,6 +228,7 @@ const char* SkDrawCommand::GetCommandString(OpType type) { case kDrawImageLattice_OpType: return "DrawImageLattice"; case kDrawImageNine_OpType: return "DrawImageNine"; case kDrawImageRect_OpType: return "DrawImageRect"; + case kDrawImageSet_OpType: return "DrawImageSet"; case kDrawOval_OpType: return "DrawOval"; case kDrawPaint_OpType: return "DrawPaint"; case kDrawPatch_OpType: return "DrawPatch"; @@ -1552,6 +1554,22 @@ Json::Value SkDrawImageRectCommand::toJSON(UrlDataManager& urlDataManager) const return result; } +SkDrawImageSetCommand::SkDrawImageSetCommand(const SkCanvas::ImageSetEntry set[], int count, + float alpha, SkFilterQuality filterQuality, + SkBlendMode mode) + : INHERITED(kDrawImageSet_OpType) + , fSet(count) + , fCount(count) + , fAlpha(alpha) + , fFilterQuality(filterQuality) + , fMode(mode) { + std::copy_n(set, count, fSet.get()); +} + +void SkDrawImageSetCommand::execute(SkCanvas* canvas) const { + canvas->experimental_DrawImageSetV0(fSet.get(), fCount, fAlpha, fFilterQuality, fMode); +} + SkDrawImageNineCommand::SkDrawImageNineCommand(const SkImage* image, const SkIRect& center, const SkRect& dst, const SkPaint* paint) : INHERITED(kDrawImageNine_OpType) diff --git a/tools/debugger/SkDrawCommand.h b/tools/debugger/SkDrawCommand.h index 2acc504599..9a84e9a185 100644 --- a/tools/debugger/SkDrawCommand.h +++ b/tools/debugger/SkDrawCommand.h @@ -43,6 +43,7 @@ public: kDrawImageLattice_OpType, kDrawImageNine_OpType, kDrawImageRect_OpType, + kDrawImageSet_OpType, kDrawOval_OpType, kDrawArc_OpType, kDrawPaint_OpType, @@ -363,6 +364,22 @@ private: typedef SkDrawCommand INHERITED; }; +class SkDrawImageSetCommand : public SkDrawCommand { +public: + SkDrawImageSetCommand(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality, + SkBlendMode); + void execute(SkCanvas* canvas) const override; + +private: + SkAutoTArray fSet; + int fCount; + float fAlpha; + SkFilterQuality fFilterQuality; + SkBlendMode fMode; + + typedef SkDrawCommand INHERITED; +}; + class SkDrawOvalCommand : public SkDrawCommand { public: SkDrawOvalCommand(const SkRect& oval, const SkPaint& paint);