diff options
-rw-r--r-- | gm/vertices.cpp | 146 | ||||
-rw-r--r-- | gn/core.gni | 1 | ||||
-rw-r--r-- | include/core/SkCanvas.h | 30 | ||||
-rwxr-xr-x | include/core/SkVertices.h | 141 | ||||
-rw-r--r-- | include/gpu/GrRenderTargetContext.h | 15 | ||||
-rw-r--r-- | include/utils/SkDumpCanvas.h | 5 | ||||
-rw-r--r-- | include/utils/SkLuaCanvas.h | 4 | ||||
-rw-r--r-- | include/utils/SkNoDrawCanvas.h | 5 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 33 | ||||
-rw-r--r-- | src/core/SkDevice.cpp | 21 | ||||
-rw-r--r-- | src/core/SkDevice.h | 2 | ||||
-rw-r--r-- | src/core/SkPictureRecord.h | 5 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetContext.cpp | 26 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetOpList.cpp | 4 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 94 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.h | 2 | ||||
-rw-r--r-- | src/gpu/SkGrPriv.h | 16 | ||||
-rw-r--r-- | src/gpu/ops/GrDrawVerticesOp.cpp | 258 | ||||
-rw-r--r-- | src/gpu/ops/GrDrawVerticesOp.h | 89 | ||||
-rw-r--r-- | tools/debugger/SkDebugCanvas.h | 5 |
20 files changed, 664 insertions, 238 deletions
diff --git a/gm/vertices.cpp b/gm/vertices.cpp index 8cfb164c5e..5fdce92a8e 100644 --- a/gm/vertices.cpp +++ b/gm/vertices.cpp @@ -10,6 +10,7 @@ #include "SkColorFilter.h" #include "SkGradientShader.h" #include "SkRandom.h" +#include "SkVertices.h" static constexpr SkScalar kShaderSize = 40; static sk_sp<SkShader> make_shader1() { @@ -39,6 +40,7 @@ static constexpr uint16_t kMeshFan[] = { 0, 1, 2, 5, 8, 7, 6, 3, 0 }; +static const int kMeshIndexCnt = (int)SK_ARRAY_COUNT(kMeshFan); static const int kMeshVertexCnt = 9; static void fill_mesh(SkPoint pts[kMeshVertexCnt], SkPoint texs[kMeshVertexCnt], @@ -76,9 +78,11 @@ class VerticesGM : public skiagm::GM { sk_sp<SkShader> fShader1; sk_sp<SkShader> fShader2; sk_sp<SkColorFilter> fColorFilter; + sk_sp<SkVertices> fVertices; + bool fUseObject; public: - VerticesGM() {} + VerticesGM(bool useObject) : fUseObject(useObject) {} protected: @@ -87,10 +91,27 @@ protected: fShader1 = make_shader1(); fShader2 = make_shader2(); fColorFilter = make_color_filter(); + if (fUseObject) { + std::unique_ptr<SkPoint[]> points(new SkPoint[kMeshVertexCnt]); + std::unique_ptr<SkPoint[]> texs(new SkPoint[kMeshVertexCnt]); + std::unique_ptr<SkColor[]> colors(new SkColor[kMeshVertexCnt]); + std::unique_ptr<uint16_t[]> indices(new uint16_t[kMeshIndexCnt]); + memcpy(points.get(), fPts, sizeof(SkPoint) * kMeshVertexCnt); + memcpy(colors.get(), fColors, sizeof(SkColor) * kMeshVertexCnt); + memcpy(texs.get(), fTexs, sizeof(SkPoint) * kMeshVertexCnt); + memcpy(indices.get(), kMeshFan, sizeof(uint16_t) * kMeshIndexCnt); + fVertices = SkVertices::MakeIndexed(SkCanvas::kTriangleFan_VertexMode, + std::move(points), + std::move(colors), std::move(texs), kMeshVertexCnt, + std::move(indices), kMeshIndexCnt); + } } SkString onShortName() override { SkString name("vertices"); + if (fUseObject) { + name.append("_object"); + } return name; } @@ -99,39 +120,6 @@ protected: } void onDraw(SkCanvas* canvas) override { - const struct { - const SkColor* fColors; - const SkPoint* fTexs; - const sk_sp<SkShader>& fShader; - const sk_sp<SkColorFilter>& fColorFilter; - uint8_t fAlpha; - } rec[] = { - { fColors, nullptr, fShader1, nullptr , 0xFF }, - { nullptr, fTexs , fShader1, nullptr , 0xFF }, - { fColors, fTexs , fShader1, nullptr , 0xFF }, - { fColors, nullptr, fShader2, nullptr , 0xFF }, - { nullptr, fTexs , fShader2, nullptr , 0xFF }, - { fColors, fTexs , fShader2, nullptr , 0xFF }, - { fColors, nullptr, fShader1, fColorFilter, 0xFF }, - { nullptr, fTexs , fShader1, fColorFilter, 0xFF }, - { fColors, fTexs , fShader1, fColorFilter, 0xFF }, - { fColors, nullptr, fShader2, fColorFilter, 0xFF }, - { nullptr, fTexs , fShader2, fColorFilter, 0xFF }, - { fColors, fTexs , fShader2, fColorFilter, 0xFF }, - { fColors, nullptr, fShader1, nullptr , 0x80 }, - { nullptr, fTexs , fShader1, nullptr , 0x80 }, - { fColors, fTexs , fShader1, nullptr , 0x80 }, - { fColors, nullptr, fShader2, nullptr , 0x80 }, - { nullptr, fTexs , fShader2, nullptr , 0x80 }, - { fColors, fTexs , fShader2, nullptr , 0x80 }, - { fColors, nullptr, fShader1, fColorFilter, 0x80 }, - { nullptr, fTexs , fShader1, fColorFilter, 0x80 }, - { fColors, fTexs , fShader1, fColorFilter, 0x80 }, - { fColors, nullptr, fShader2, fColorFilter, 0x80 }, - { nullptr, fTexs , fShader2, fColorFilter, 0x80 }, - { fColors, fTexs , fShader2, fColorFilter, 0x80 }, - }; - const SkBlendMode modes[] = { SkBlendMode::kClear, SkBlendMode::kSrc, @@ -168,18 +156,38 @@ protected: canvas->translate(4, 4); int x = 0; - for (size_t j = 0; j < SK_ARRAY_COUNT(modes); ++j) { + for (auto mode : modes) { canvas->save(); - for (size_t i = 0; i < SK_ARRAY_COUNT(rec); ++i) { - paint.setShader(rec[i].fShader); - paint.setColorFilter(rec[i].fColorFilter); - paint.setAlpha(rec[i].fAlpha); - //if (2 == x) - canvas->drawVertices(SkCanvas::kTriangleFan_VertexMode, kMeshVertexCnt, fPts, - rec[i].fTexs, rec[i].fColors, modes[j], kMeshFan, - SK_ARRAY_COUNT(kMeshFan), paint); - canvas->translate(40, 0); - ++x; + for (uint8_t alpha : {0xFF, 0x80}) { + for (const auto& cf : {sk_sp<SkColorFilter>(nullptr), fColorFilter}) { + for (const auto& shader : {fShader1, fShader2}) { + static constexpr struct { + bool fHasColors; + bool fHasTexs; + } kAttrs[] = {{true, false}, {false, true}, {true, true}}; + for (auto attrs : kAttrs) { + paint.setShader(shader); + paint.setColorFilter(cf); + paint.setAlpha(alpha); + if (fUseObject) { + uint32_t flags = 0; + flags |= + attrs.fHasColors ? 0 : SkCanvas::kIgnoreColors_VerticesFlag; + flags |= attrs.fHasTexs ? 0 + : SkCanvas::kIgnoreTexCoords_VerticesFlag; + canvas->drawVertices(fVertices, mode, paint, flags); + } else { + const SkColor* colors = attrs.fHasColors ? fColors : nullptr; + const SkPoint* texs = attrs.fHasTexs ? fTexs : nullptr; + canvas->drawVertices(SkCanvas::kTriangleFan_VertexMode, + kMeshVertexCnt, fPts, texs, colors, mode, + kMeshFan, kMeshIndexCnt, paint); + } + canvas->translate(40, 0); + ++x; + } + } + } } canvas->restore(); canvas->translate(0, 40); @@ -192,14 +200,15 @@ private: ///////////////////////////////////////////////////////////////////////////////////// -DEF_GM(return new VerticesGM();) +DEF_GM(return new VerticesGM(true);) +DEF_GM(return new VerticesGM(false);) + +static void draw_batching(SkCanvas* canvas, bool useObject) { + std::unique_ptr<SkPoint[]> pts(new SkPoint[kMeshVertexCnt]); + std::unique_ptr<SkPoint[]> texs(new SkPoint[kMeshVertexCnt]); + std::unique_ptr<SkColor[]> colors(new SkColor[kMeshVertexCnt]); + fill_mesh(pts.get(), texs.get(), colors.get()); -// This test exists to exercise batching in the gpu backend. -DEF_SIMPLE_GM(vertices_batching, canvas, 50, 500) { - SkPoint pts[kMeshVertexCnt]; - SkPoint texs[kMeshVertexCnt]; - SkColor colors[kMeshVertexCnt]; - fill_mesh(pts, texs, colors); SkTDArray<SkMatrix> matrices; matrices.push()->reset(); matrices.push()->setTranslate(0, 40); @@ -211,13 +220,23 @@ DEF_SIMPLE_GM(vertices_batching, canvas, 50, 500) { auto shader = make_shader1(); // Triangle fans can't batch so we convert to regular triangles, - static constexpr int kNumTris = SK_ARRAY_COUNT(kMeshFan) - 2; - uint16_t indices[3 * kNumTris]; + static constexpr int kNumTris = kMeshIndexCnt - 2; + std::unique_ptr<uint16_t[]> indices(new uint16_t[3 * kNumTris]); for (size_t i = 0; i < kNumTris; ++i) { indices[3 * i] = kMeshFan[0]; indices[3 * i + 1] = kMeshFan[i + 1]; indices[3 * i + 2] = kMeshFan[i + 2]; } + + sk_sp<SkVertices> vertices; + if (useObject) { + vertices = + SkVertices::MakeIndexed(SkCanvas::kTriangles_VertexMode, std::move(pts), + std::move(colors), + std::move(texs), kMeshVertexCnt, std::move(indices), + 3 * kNumTris); + } + canvas->save(); canvas->translate(10, 10); for (bool useShader : {false, true}) { for (bool useTex : {false, true}) { @@ -225,13 +244,26 @@ DEF_SIMPLE_GM(vertices_batching, canvas, 50, 500) { canvas->save(); canvas->concat(m); SkPaint paint; - const SkPoint* t = useTex ? texs : nullptr; paint.setShader(useShader ? shader : nullptr); - canvas->drawVertices(SkCanvas::kTriangles_VertexMode, kMeshVertexCnt, pts, t, - colors, indices, SK_ARRAY_COUNT(indices), paint); + if (useObject) { + uint32_t flags = useTex ? 0 : SkCanvas::kIgnoreTexCoords_VerticesFlag; + canvas->drawVertices(vertices, SkBlendMode::kModulate, paint, flags); + } else { + const SkPoint* t = useTex ? texs.get() : nullptr; + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, kMeshVertexCnt, pts.get(), + t, colors.get(), indices.get(), kNumTris * 3, paint); + } canvas->restore(); } canvas->translate(0, 120); } } + canvas->restore(); +} + +// This test exists to exercise batching in the gpu backend. +DEF_SIMPLE_GM(vertices_batching, canvas, 100, 500) { + draw_batching(canvas, false); + canvas->translate(50, 0); + draw_batching(canvas, true); } diff --git a/gn/core.gni b/gn/core.gni index b10b628be0..12089371ee 100644 --- a/gn/core.gni +++ b/gn/core.gni @@ -442,6 +442,7 @@ skia_core_sources = [ "$_include/core/SkTypeface.h", "$_include/core/SkTypes.h", "$_include/core/SkUnPreMultiply.h", + "$_include/core/SkVertices.h", "$_include/core/SkWriter32.h", # private diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index b2bc9ed3f4..d58b7ea515 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -42,6 +42,7 @@ struct SkRSXform; class SkSurface; class SkSurface_Base; class SkTextBlob; +class SkVertices; /** \class SkCanvas @@ -1152,9 +1153,9 @@ public: in _texture_ space (not uv space) for each vertex. @param colors May be null. If not null, specifies a color for each vertex, to be interpolated across the triangle. - @param mode Used if both texs and colors are present. In this - case the colors are combined with the texture using mode, - before being drawn using the paint. + @param mode Used if both texs and colors are present and paint has a + shader. In this case the colors are combined with the texture + using mode, before being drawn using the paint. @param indices If not null, array of indices to reference into the vertex (texs, colors) array. @param indexCount number of entries in the indices array (if not null) @@ -1172,6 +1173,23 @@ public: this->drawVertices(vmode, vertexCount, vertices, texs, colors, SkBlendMode::kModulate, indices, indexCount, paint); } + enum VerticesFlags { + /** Ignore the vertices' colors and instead use the paint color. */ + kIgnoreColors_VerticesFlag = 0x1, + /** Ignore the vertices' tex coords (and any shader on the paint). */ + kIgnoreTexCoords_VerticesFlag = 0x2 + }; + /** Draw vertices from an immutable SkVertices object. + + @param vertices The mesh to draw. + @param mode Used if both texs and colors are present and paint has a + shader. In this case the colors are combined with the texture + using mode, before being drawn using the paint. + @param paint Specifies the shader/texture if present. + @param flags Allows the caller to ignore colors or texs on vertices. + */ + void drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint, + uint32_t flags = 0); /** Draw a cubic coons patch @@ -1424,6 +1442,12 @@ protected: virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkBlendMode, const uint16_t indices[], int indexCount, const SkPaint&); + virtual void onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode mode, + const SkPaint& paint, uint32_t flags); + // Subclasses can use this put the vertices object call on the regular draw vertices code path. + // This is temporary until we teach recording and other SkCanvas classes about SkVertices. + void onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode, + const SkPaint& paint, uint32_t flags); virtual void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int count, SkBlendMode, const SkRect* cull, const SkPaint*); diff --git a/include/core/SkVertices.h b/include/core/SkVertices.h new file mode 100755 index 0000000000..9b94372d7c --- /dev/null +++ b/include/core/SkVertices.h @@ -0,0 +1,141 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkVertices_DEFINED +#define SkVertices_DEFINED + +#include "SkCanvas.h" +#include "SkColor.h" +#include "SkPoint.h" +#include "SkRect.h" +#include "SkRefCnt.h" + +/** + * An immutable set of vertex data that can be used with SkCanvas::drawVertices. Clients are + * encouraged to provide a bounds on the vertex positions if they can compute one more cheaply than + * looping over the positions. + */ +class SkVertices : public SkNVRefCnt<SkVertices> { +public: + static sk_sp<SkVertices> Make(SkCanvas::VertexMode mode, + std::unique_ptr<const SkPoint[]> positions, + std::unique_ptr<const SkColor[]> colors, /* optional */ + std::unique_ptr<const SkPoint[]> texs, /* optional */ + int vertexCnt) { + if (!positions || vertexCnt <= 0) { + return nullptr; + } + return sk_sp<SkVertices>(new SkVertices(mode, std::move(positions), std::move(colors), + std::move(texs), vertexCnt, nullptr, 0, nullptr)); + } + + static sk_sp<SkVertices> Make(SkCanvas::VertexMode mode, + std::unique_ptr<const SkPoint[]> positions, + std::unique_ptr<const SkColor[]> colors, /* optional */ + std::unique_ptr<const SkPoint[]> texs, /* optional */ + int vertexCnt, + const SkRect& bounds) { + if (!positions || vertexCnt <= 0) { + return nullptr; + } + return sk_sp<SkVertices>(new SkVertices(mode, std::move(positions), std::move(colors), + std::move(texs), vertexCnt, nullptr, 0, &bounds)); + } + + static sk_sp<SkVertices> MakeIndexed(SkCanvas::VertexMode mode, + std::unique_ptr<const SkPoint[]> positions, + std::unique_ptr<const SkColor[]> colors, /* optional */ + std::unique_ptr<const SkPoint[]> texs, /* optional */ + int vertexCnt, + std::unique_ptr<const uint16_t[]> indices, + int indexCnt) { + if (!positions || !indices || vertexCnt <= 0 || indexCnt <= 0) { + return nullptr; + } + return sk_sp<SkVertices>(new SkVertices(mode, std::move(positions), std::move(colors), + std::move(texs), vertexCnt, std::move(indices), + indexCnt, nullptr)); + } + + static sk_sp<SkVertices> MakeIndexed(SkCanvas::VertexMode mode, + std::unique_ptr<const SkPoint[]> positions, + std::unique_ptr<const SkColor[]> colors, /* optional */ + std::unique_ptr<const SkPoint[]> texs, /* optional */ + int vertexCnt, + std::unique_ptr<const uint16_t[]> indices, + int indexCnt, + const SkRect& bounds) { + if (!positions || !indices || vertexCnt <= 0 || indexCnt <= 0) { + return nullptr; + } + return sk_sp<SkVertices>(new SkVertices(mode, std::move(positions), std::move(colors), + std::move(texs), vertexCnt, std::move(indices), + indexCnt, &bounds)); + } + + SkCanvas::VertexMode mode() const { return fMode; } + + int vertexCount() const { return fVertexCnt; } + bool hasColors() const { return SkToBool(fColors); } + bool hasTexCoords() const { return SkToBool(fTexs); } + const SkPoint* positions() const { return fPositions.get(); } + const SkPoint* texCoords() const { return fTexs.get(); } + const SkColor* colors() const { return fColors.get(); } + + bool isIndexed() const { return SkToBool(fIndexCnt); } + int indexCount() const { return fIndexCnt; } + const uint16_t* indices() const { return fIndices.get(); } + + size_t size() const { + return fVertexCnt * (sizeof(SkPoint) * (this->hasTexCoords() ? 2 : 1) + sizeof(SkColor)) + + fIndexCnt * sizeof(uint16_t); + } + + const SkRect& bounds() const { return fBounds; } + +private: + SkVertices(SkCanvas::VertexMode mode, std::unique_ptr<const SkPoint[]> positions, + std::unique_ptr<const SkColor[]> colors, std::unique_ptr<const SkPoint[]> texs, + int vertexCnt, std::unique_ptr<const uint16_t[]> indices, int indexCnt, + const SkRect* bounds) + : fMode(mode) + , fVertexCnt(vertexCnt) + , fIndexCnt(indexCnt) + , fPositions(std::move(positions)) + , fColors(std::move(colors)) + , fTexs(std::move(texs)) + , fIndices(std::move(indices)) { + SkASSERT(SkToBool(fPositions) && SkToBool(fVertexCnt)); + SkASSERT(SkToBool(fIndices) == SkToBool(fIndexCnt)); + if (bounds) { +#ifdef SK_DEBUG + fBounds.setBounds(fPositions.get(), fVertexCnt); + SkASSERT(bounds->fLeft <= fBounds.fLeft && bounds->fRight >= fBounds.fRight && + bounds->fTop <= fBounds.fTop && bounds->fBottom >= fBounds.fBottom); +#endif + fBounds = *bounds; + } else { + fBounds.setBounds(fPositions.get(), fVertexCnt); + } +#ifdef SK_DEBUG + for (int i = 0; i < fIndexCnt; ++i) { + SkASSERT(fIndices[i] < fVertexCnt); + } +#endif + } + + SkCanvas::VertexMode fMode; + int fVertexCnt; + int fIndexCnt; + std::unique_ptr<const SkPoint[]> fPositions; + std::unique_ptr<const SkColor[]> fColors; + std::unique_ptr<const SkPoint[]> fTexs; + std::unique_ptr<const uint16_t[]> fIndices; + SkRect fBounds; +}; + +#endif diff --git a/include/gpu/GrRenderTargetContext.h b/include/gpu/GrRenderTargetContext.h index 403de56f34..11b1c531e0 100644 --- a/include/gpu/GrRenderTargetContext.h +++ b/include/gpu/GrRenderTargetContext.h @@ -42,6 +42,7 @@ class SkRegion; class SkRRect; struct SkRSXform; class SkTextBlob; +class SkVertices; /** * A helper object to orchestrate commands (draws, etc...) for GrSurfaces that are GrRenderTargets. @@ -230,6 +231,20 @@ public: ColorArrayType = ColorArrayType::kPremulGrColor); /** + * Draws vertices with a paint. + * + * @param paint describes how to color pixels. + * @param viewMatrix transformation matrix + * @param veritces specifies the mesh to draw. + * @param flags A bitfield of options specified by SkCanvas::VerticesFlags. + */ + void drawVertices(const GrClip&, + GrPaint&& paint, + const SkMatrix& viewMatrix, + sk_sp<SkVertices> vertices, + uint32_t flags); + + /** * Draws textured sprites from an atlas with a paint. This currently does not support AA for the * sprite rectangle edges. * diff --git a/include/utils/SkDumpCanvas.h b/include/utils/SkDumpCanvas.h index c8f977ec10..79a49bcd3b 100644 --- a/include/utils/SkDumpCanvas.h +++ b/include/utils/SkDumpCanvas.h @@ -9,6 +9,7 @@ #define SkDumpCanvas_DEFINED #include "SkCanvas.h" +#include "SkVertices.h" /** This class overrides all the draw methods on SkCanvas, and formats them as text, and then sends that to a Dumper helper object. @@ -116,6 +117,10 @@ protected: const SkColor colors[], SkBlendMode, const uint16_t indices[], int indexCount, const SkPaint&) override; + void onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint, + uint32_t flags) override { + this->onDrawVerticesObjectFallback(std::move(vertices), mode, paint, flags); + } void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; diff --git a/include/utils/SkLuaCanvas.h b/include/utils/SkLuaCanvas.h index 357ddc81da..805c2e14b6 100644 --- a/include/utils/SkLuaCanvas.h +++ b/include/utils/SkLuaCanvas.h @@ -62,6 +62,10 @@ protected: const SkColor colors[], SkBlendMode, const uint16_t indices[], int indexCount, const SkPaint&) override; + void onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint, + uint32_t flags) override { + this->onDrawVerticesObjectFallback(std::move(vertices), mode, paint, flags); + } void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; diff --git a/include/utils/SkNoDrawCanvas.h b/include/utils/SkNoDrawCanvas.h index 316a1c0e02..14b85549f4 100644 --- a/include/utils/SkNoDrawCanvas.h +++ b/include/utils/SkNoDrawCanvas.h @@ -9,6 +9,7 @@ #define SkNoDrawCanvas_DEFINED #include "SkCanvas.h" +#include "SkVertices.h" struct SkIRect; @@ -67,6 +68,10 @@ protected: const SkPaint*) override {} void onDrawVertices(VertexMode, int, const SkPoint[], const SkPoint[], const SkColor[], SkBlendMode, const uint16_t[], int, const SkPaint&) override {} + void onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint, + uint32_t flags) override { + this->onDrawVerticesObjectFallback(std::move(vertices), mode, paint, flags); + } void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, SkBlendMode, const SkRect*, const SkPaint*) override {} diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 41c5116718..eb81bd7951 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -49,6 +49,7 @@ #endif #include "SkClipOpPriv.h" +#include "SkVertices.h" #define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0) @@ -1857,8 +1858,14 @@ void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], con void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkBlendMode bmode, const uint16_t indices[], int indexCount, const SkPaint& paint) { - this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, bmode, - indices, indexCount, paint); + this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices, + indexCount, paint); +} + +void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint, + uint32_t flags) { + RETURN_ON_NULL(vertices); + this->onDrawVerticesObject(std::move(vertices), mode, paint, flags); } void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { @@ -2815,6 +2822,28 @@ void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount, LOOPER_END } +void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode, + const SkPaint& paint, uint32_t flags) { + TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()"); + LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr) + + while (iter.next()) { + // In the common case of one iteration we could std::move vertices here. + iter.fDevice->drawVerticesObject(iter, vertices, bmode, looper.paint(), flags); + } + + LOOPER_END +} + +void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode, + const SkPaint& paint, uint32_t flags) { + const SkPoint* texs = + (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords(); + const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors(); + this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs, + colors, mode, vertices->indices(), vertices->indexCount(), paint); +} + void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], SkBlendMode bmode, const SkPaint& paint) { diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 8042c16f2c..07b9c23373 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -5,26 +5,27 @@ * found in the LICENSE file. */ -#include "SkColorFilter.h" #include "SkDevice.h" +#include "SkColorFilter.h" #include "SkDraw.h" #include "SkDrawFilter.h" -#include "SkImage_Base.h" #include "SkImageCacherator.h" #include "SkImageFilter.h" #include "SkImageFilterCache.h" #include "SkImagePriv.h" +#include "SkImage_Base.h" #include "SkLatticeIter.h" #include "SkPatchUtils.h" -#include "SkPathPriv.h" #include "SkPathMeasure.h" -#include "SkRasterClip.h" +#include "SkPathPriv.h" #include "SkRSXform.h" +#include "SkRasterClip.h" #include "SkShader.h" #include "SkSpecialImage.h" +#include "SkTLazy.h" #include "SkTextBlobRunIterator.h" #include "SkTextToPathIter.h" -#include "SkTLazy.h" +#include "SkVertices.h" SkBaseDevice::SkBaseDevice(const SkImageInfo& info, const SkSurfaceProps& surfaceProps) : fInfo(info) @@ -309,6 +310,16 @@ void SkBaseDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkR } } +void SkBaseDevice::drawVerticesObject(const SkDraw& draw, sk_sp<SkVertices> vertices, + SkBlendMode mode, const SkPaint& paint, uint32_t flags) { + const SkPoint* texs = + (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords(); + const SkColor* colors = + (flags & SkCanvas::kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors(); + this->drawVertices(draw, vertices->mode(), vertices->vertexCount(), vertices->positions(), texs, + colors, mode, vertices->indices(), vertices->indexCount(), paint); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// void SkBaseDevice::drawSpecial(const SkDraw&, SkSpecialImage*, int x, int y, const SkPaint&) {} diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h index ab0fdbd734..92396725a4 100644 --- a/src/core/SkDevice.h +++ b/src/core/SkDevice.h @@ -198,6 +198,8 @@ protected: const SkColor colors[], SkBlendMode, const uint16_t indices[], int indexCount, const SkPaint& paint) = 0; + virtual void drawVerticesObject(const SkDraw&, sk_sp<SkVertices>, SkBlendMode, const SkPaint&, + uint32_t flags); // default implementation unrolls the blob runs. virtual void drawTextBlob(const SkDraw&, const SkTextBlob*, SkScalar x, SkScalar y, const SkPaint& paint, SkDrawFilter* drawFilter); diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h index 9339d12ba5..587233c298 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -15,6 +15,7 @@ #include "SkTArray.h" #include "SkTDArray.h" #include "SkTHash.h" +#include "SkVertices.h" #include "SkWriter32.h" // These macros help with packing and unpacking a single byte value and @@ -203,6 +204,10 @@ protected: const SkColor colors[], SkBlendMode, const uint16_t indices[], int indexCount, const SkPaint&) override; + void onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint, + uint32_t flags) override { + this->onDrawVerticesObjectFallback(std::move(vertices), mode, paint, flags); + } void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index c0b25dedcf..8e90b04ee5 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -898,12 +898,34 @@ void GrRenderTargetContext::drawVertices(const GrClip& clip, return; } - viewMatrix.mapRect(&bounds); - std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make( paint.getColor(), primitiveType, viewMatrix, positions, vertexCount, indices, indexCount, colors, texCoords, bounds, colorArrayType); + if (!op) { + return; + } + GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone); + this->getOpList()->addDrawOp(pipelineBuilder, this, clip, std::move(op)); +} +void GrRenderTargetContext::drawVertices(const GrClip& clip, + GrPaint&& paint, + const SkMatrix& viewMatrix, + sk_sp<SkVertices> vertices, + uint32_t flags) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawVertices"); + + AutoCheckFlush acf(this->drawingManager()); + + SkASSERT(vertices); + std::unique_ptr<GrDrawOp> op = + GrDrawVerticesOp::Make(paint.getColor(), std::move(vertices), viewMatrix, flags); + if (!op) { + return; + } GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone); this->getOpList()->addDrawOp(pipelineBuilder, this, clip, std::move(op)); } diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp index 1c0243ba14..69ba279434 100644 --- a/src/gpu/GrRenderTargetOpList.cpp +++ b/src/gpu/GrRenderTargetOpList.cpp @@ -466,7 +466,7 @@ GrOp* GrRenderTargetOpList::recordOp(std::unique_ptr<GrOp> op, // 2) intersect with something // 3) find a 'blocker' GR_AUDIT_TRAIL_ADD_OP(fAuditTrail, op.get(), renderTargetID); - GrOP_INFO("Re-Recording (%s, B%u)\n" + GrOP_INFO("Recording (%s, B%u)\n" "\tBounds LRTB (%f, %f, %f, %f)\n", op->name(), op->uniqueID(), @@ -492,6 +492,8 @@ GrOp* GrRenderTargetOpList::recordOp(std::unique_ptr<GrOp> op, if (candidate.fOp->combineIfPossible(op.get(), *this->caps())) { GrOP_INFO("\t\tCombining with (%s, B%u)\n", candidate.fOp->name(), candidate.fOp->uniqueID()); + GrOP_INFO("\t\t\tCombined op info:\n"); + GrOP_INFO(SkTabString(candidate.fOp->dumpInfo(), 4).c_str()); GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(fAuditTrail, candidate.fOp.get(), op.get()); join(&fRecordedOps.fromBack(i).fClippedBounds, fRecordedOps.fromBack(i).fClippedBounds, clippedBounds); diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index b658def522..4068c2b102 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -14,10 +14,10 @@ #include "GrImageTextureMaker.h" #include "GrRenderTargetContextPriv.h" #include "GrStyle.h" +#include "GrSurfaceContextPriv.h" #include "GrTextureAdjuster.h" #include "GrTextureProxy.h" #include "GrTracing.h" - #include "SkCanvasPriv.h" #include "SkDraw.h" #include "SkGlyphCache.h" @@ -44,6 +44,7 @@ #include "SkTLazy.h" #include "SkUtils.h" #include "SkVertState.h" +#include "SkVertices.h" #include "SkWritePixelsRec.h" #include "effects/GrBicubicEffect.h" #include "effects/GrSimpleTextureEffect.h" @@ -1568,14 +1569,30 @@ void SkGpuDevice::drawBitmapLattice(const SkDraw& draw, const SkBitmap& bitmap, this->drawProducerLattice(draw, &maker, lattice, dst, paint); } -/////////////////////////////////////////////////////////////////////////////// - -// must be in SkCanvas::VertexMode order -static const GrPrimitiveType gVertexMode2PrimitiveType[] = { - kTriangles_GrPrimitiveType, - kTriangleStrip_GrPrimitiveType, - kTriangleFan_GrPrimitiveType, -}; +bool init_vertices_paint(const SkPaint& skPaint, const SkMatrix& matrix, SkBlendMode bmode, + bool hasTexs, bool hasColors, GrRenderTargetContext* rtc, + GrPaint* grPaint) { + GrContext* context = rtc->surfPriv().getContext(); + if (hasTexs && skPaint.getShader()) { + if (hasColors) { + // When there are texs and colors the shader and colors are combined using bmode. + return SkPaintToGrPaintWithXfermode(context, rtc, skPaint, matrix, bmode, false, + grPaint); + } else { + // We have a shader, but no colors to blend it against. + return SkPaintToGrPaint(context, rtc, skPaint, matrix, grPaint); + } + } else { + if (hasColors) { + // We have colors, but either have no shader or no texture coords (which implies that + // we should ignore the shader). + return SkPaintToGrPaintWithPrimitiveColor(context, rtc, skPaint, grPaint); + } else { + // No colors and no shaders. Just draw with the paint color. + return (!SkPaintToGrPaintNoShader(context, rtc, skPaint, grPaint)); + } + } +} void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, int vertexCount, const SkPoint vertices[], @@ -1645,40 +1662,13 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, return; } - GrPrimitiveType primType = gVertexMode2PrimitiveType[vmode]; + GrPrimitiveType primType = SkVertexModeToGrPrimitiveType(vmode); GrPaint grPaint; - if (texs && paint.getShader()) { - if (colors) { - // When there are texs and colors the shader and colors are combined using bmode. - if (!SkPaintToGrPaintWithXfermode(this->context(), fRenderTargetContext.get(), paint, - *draw.fMatrix, bmode, false, &grPaint)) { - return; - } - } else { - // We have a shader, but no colors to blend it against. - if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, *draw.fMatrix, - &grPaint)) { - return; - } - } - } else { - if (colors) { - // We have colors, but either have no shader or no texture coords (which implies that - // we should ignore the shader). - if (!SkPaintToGrPaintWithPrimitiveColor(this->context(), fRenderTargetContext.get(), - paint, &grPaint)) { - return; - } - } else { - // No colors and no shaders. Just draw with the paint color. - if (!SkPaintToGrPaintNoShader(this->context(), fRenderTargetContext.get(), paint, - &grPaint)) { - return; - } - } + if (!init_vertices_paint(paint, *draw.fMatrix, bmode, SkToBool(texs), SkToBool(colors), + fRenderTargetContext.get(), &grPaint)) { + return; } - fRenderTargetContext->drawVertices(fClip, std::move(grPaint), *draw.fMatrix, @@ -1692,6 +1682,30 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, GrRenderTargetContext::ColorArrayType::kSkColor); } +void SkGpuDevice::drawVerticesObject(const SkDraw& draw, sk_sp<SkVertices> vertices, + SkBlendMode mode, const SkPaint& paint, uint32_t flags) { + ASSERT_SINGLE_OWNER + CHECK_SHOULD_DRAW(draw); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVerticesObject", fContext.get()); + + SkASSERT(vertices); + GrPaint grPaint; + bool hasColors = vertices->hasColors() && !(SkCanvas::kIgnoreColors_VerticesFlag & flags); + bool hasTexs = vertices->hasTexCoords() & !(SkCanvas::kIgnoreTexCoords_VerticesFlag & flags); + if (!hasTexs && !hasColors) { + // The dreaded wireframe mode. Fallback to drawVertices and go so slooooooow. + this->drawVertices(draw, vertices->mode(), vertices->vertexCount(), vertices->positions(), + nullptr, nullptr, mode, vertices->indices(), vertices->indexCount(), + paint); + } + if (!init_vertices_paint(paint, *draw.fMatrix, mode, hasTexs, hasColors, + fRenderTargetContext.get(), &grPaint)) { + return; + } + fRenderTargetContext->drawVertices(fClip, std::move(grPaint), *draw.fMatrix, + std::move(vertices), flags); +} + /////////////////////////////////////////////////////////////////////////////// void SkGpuDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkRSXform xform[], diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h index 29452146d1..846a7e5798 100644 --- a/src/gpu/SkGpuDevice.h +++ b/src/gpu/SkGpuDevice.h @@ -93,6 +93,8 @@ public: void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount, const SkPoint verts[], const SkPoint texs[], const SkColor colors[], SkBlendMode, const uint16_t indices[], int indexCount, const SkPaint&) override; + void drawVerticesObject(const SkDraw&, sk_sp<SkVertices>, SkBlendMode, const SkPaint&, + uint32_t flags) override; void drawAtlas(const SkDraw&, const SkImage* atlas, const SkRSXform[], const SkRect[], const SkColor[], int count, SkBlendMode, const SkPaint&) override; void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, const SkPaint&) override; diff --git a/src/gpu/SkGrPriv.h b/src/gpu/SkGrPriv.h index 9e2aad0ccd..5437d4a07c 100644 --- a/src/gpu/SkGrPriv.h +++ b/src/gpu/SkGrPriv.h @@ -10,6 +10,7 @@ #include "GrBlend.h" #include "GrTypes.h" +#include "SkCanvas.h" #include "SkImageInfo.h" #include "SkMatrix.h" #include "SkPM4f.h" @@ -103,6 +104,21 @@ bool SkPaintToGrPaintWithTexture(GrContext* context, ////////////////////////////////////////////////////////////////////////////// +static inline GrPrimitiveType SkVertexModeToGrPrimitiveType(const SkCanvas::VertexMode mode) { + switch (mode) { + case SkCanvas::kTriangles_VertexMode: + return kTriangles_GrPrimitiveType; + case SkCanvas::kTriangleStrip_VertexMode: + return kTriangleStrip_GrPrimitiveType; + case SkCanvas::kTriangleFan_VertexMode: + return kTriangleFan_GrPrimitiveType; + } + SkFAIL("Invalid mode"); + return kPoints_GrPrimitiveType; +} + +////////////////////////////////////////////////////////////////////////////// + static inline SkPM4f GrColor4fToSkPM4f(const GrColor4f& c) { SkPM4f pm4f; pm4f.fVec[SkPM4f::R] = c.fRGBA[0]; diff --git a/src/gpu/ops/GrDrawVerticesOp.cpp b/src/gpu/ops/GrDrawVerticesOp.cpp index 43093cee5b..7420a5275a 100644 --- a/src/gpu/ops/GrDrawVerticesOp.cpp +++ b/src/gpu/ops/GrDrawVerticesOp.cpp @@ -6,87 +6,99 @@ */ #include "GrDrawVerticesOp.h" - #include "GrDefaultGeoProcFactory.h" -#include "GrInvariantOutput.h" #include "GrOpFlushState.h" +#include "SkGrPriv.h" -static sk_sp<GrGeometryProcessor> make_gp(bool clientProvidedLocalCoords, - bool pipelineReadsLocalCoords, - GrRenderTargetContext::ColorArrayType colorArrayType, - bool multipleViewMatrices, - const SkMatrix& viewMatrixIfCommon, - bool* hasLocalCoordAttribute) { - using namespace GrDefaultGeoProcFactory; - LocalCoords::Type localCoordsType; - if (pipelineReadsLocalCoords) { - if (clientProvidedLocalCoords || multipleViewMatrices) { - *hasLocalCoordAttribute = true; - localCoordsType = LocalCoords::kHasExplicit_Type; - } else { - *hasLocalCoordAttribute = false; - localCoordsType = LocalCoords::kUsePosition_Type; - } +std::unique_ptr<GrDrawOp> GrDrawVerticesOp::Make( + GrColor color, GrPrimitiveType primitiveType, const SkMatrix& viewMatrix, + const SkPoint* positions, int vertexCount, const uint16_t* indices, int indexCount, + const uint32_t* colors, const SkPoint* localCoords, const SkRect& bounds, + GrRenderTargetContext::ColorArrayType colorArrayType) { + SkASSERT(positions); + std::unique_ptr<SkPoint[]> pos(new SkPoint[vertexCount]); + memcpy(pos.get(), positions, sizeof(SkPoint) * vertexCount); + std::unique_ptr<SkColor[]> col; + if (colors) { + col.reset(new SkColor[vertexCount]); + memcpy(col.get(), colors, sizeof(SkColor) * vertexCount); } else { - localCoordsType = LocalCoords::kUnused_Type; - *hasLocalCoordAttribute = false; + // When we tessellate we will fill a color array with the GrColor value passed above as + // 'color'. + colorArrayType = GrRenderTargetContext::ColorArrayType::kPremulGrColor; + } + std::unique_ptr<SkPoint[]> lc; + if (localCoords) { + lc.reset(new SkPoint[vertexCount]); + memcpy(lc.get(), localCoords, sizeof(SkPoint) * vertexCount); } + std::unique_ptr<uint16_t[]> idx; + if (indexCount) { + idx.reset(new uint16_t[indexCount]); + memcpy(idx.get(), indices, sizeof(uint16_t) * indexCount); + } + static constexpr SkCanvas::VertexMode kIgnoredMode = SkCanvas::kTriangles_VertexMode; + sk_sp<SkVertices> vertices; + if (indices) { + vertices = SkVertices::MakeIndexed(kIgnoredMode, std::move(pos), std::move(col), + std::move(lc), + vertexCount, std::move(idx), indexCount, bounds); + } else { + vertices = SkVertices::Make(kIgnoredMode, std::move(pos), std::move(col), std::move(lc), + vertexCount, bounds); + } + if (!vertices) { + return nullptr; + } + return std::unique_ptr<GrDrawOp>(new GrDrawVerticesOp(std::move(vertices), primitiveType, color, + colorArrayType, viewMatrix)); +} - Color::Type colorType = - (colorArrayType == GrRenderTargetContext::ColorArrayType::kPremulGrColor) - ? Color::kPremulGrColorAttribute_Type - : Color::kUnpremulSkColorAttribute_Type; - const SkMatrix& vm = multipleViewMatrices ? SkMatrix::I() : viewMatrixIfCommon; - return GrDefaultGeoProcFactory::Make(colorType, Coverage::kSolid_Type, localCoordsType, vm); +std::unique_ptr<GrDrawOp> GrDrawVerticesOp::Make(GrColor color, sk_sp<SkVertices> vertices, + const SkMatrix& viewMatrix, uint32_t flags) { + SkASSERT(vertices); + GrPrimitiveType primType = SkVertexModeToGrPrimitiveType(vertices->mode()); + return std::unique_ptr<GrDrawOp>(new GrDrawVerticesOp( + std::move(vertices), primType, color, GrRenderTargetContext::ColorArrayType::kSkColor, + viewMatrix, flags)); } -GrDrawVerticesOp::GrDrawVerticesOp(GrColor color, GrPrimitiveType primitiveType, - const SkMatrix& viewMatrix, const SkPoint* positions, - int vertexCount, const uint16_t* indices, int indexCount, - const uint32_t* colors, const SkPoint* localCoords, - const SkRect& bounds, - GrRenderTargetContext::ColorArrayType colorArrayType) - : INHERITED(ClassID()) { - SkASSERT(positions); +GrDrawVerticesOp::GrDrawVerticesOp(sk_sp<SkVertices> vertices, GrPrimitiveType primitiveType, + GrColor color, + GrRenderTargetContext::ColorArrayType colorArrayType, + const SkMatrix& viewMatrix, uint32_t flags) + : INHERITED(ClassID()), fColorArrayType(colorArrayType) { + SkASSERT(vertices); + + fVertexCount = vertices->vertexCount(); + fIndexCount = vertices->indexCount(); + fPrimitiveType = primitiveType; Mesh& mesh = fMeshes.push_back(); mesh.fColor = color; mesh.fViewMatrix = viewMatrix; + mesh.fVertices = std::move(vertices); + mesh.fFlags = flags; - mesh.fPositions.append(vertexCount, positions); - if (indices) { - mesh.fIndices.append(indexCount, indices); + fFlags = 0; + if (mesh.hasPerVertexColors()) { + fFlags |= kRequiresPerVertexColors_Flag; } - - if (colors) { - fVariableColor = true; - mesh.fColors.append(vertexCount, colors); - fColorArrayType = colorArrayType; - } else { - fVariableColor = false; - // When we tessellate we will fill a color array with the GrColor value passed above as - // 'color'. - fColorArrayType = GrRenderTargetContext::ColorArrayType::kPremulGrColor; + if (mesh.hasExplicitLocalCoords()) { + fFlags |= kAnyMeshHasExplicitLocalCoords; } - if (localCoords) { - mesh.fLocalCoords.append(vertexCount, localCoords); - } - fVertexCount = vertexCount; - fIndexCount = indexCount; - fPrimitiveType = primitiveType; - IsZeroArea zeroArea; if (GrIsPrimTypeLines(primitiveType) || kPoints_GrPrimitiveType == primitiveType) { zeroArea = IsZeroArea::kYes; } else { zeroArea = IsZeroArea::kNo; } - this->setBounds(bounds, HasAABloat::kNo, zeroArea); + this->setTransformedBounds(mesh.fVertices->bounds(), viewMatrix, HasAABloat::kNo, zeroArea); } void GrDrawVerticesOp::getPipelineAnalysisInput(GrPipelineAnalysisDrawOpInput* input) const { - if (fVariableColor) { + if (this->requiresPerVertexColors()) { input->pipelineColorInput()->setUnknownFourComponents(); } else { input->pipelineColorInput()->setKnownFourComponents(fMeshes[0].fColor); @@ -99,25 +111,58 @@ void GrDrawVerticesOp::applyPipelineOptimizations(const GrPipelineOptimizations& GrColor overrideColor; if (optimizations.getOverrideColorIfSet(&overrideColor)) { fMeshes[0].fColor = overrideColor; - fMeshes[0].fColors.reset(); - fVariableColor = false; + fMeshes[0].fFlags |= SkCanvas::kIgnoreColors_VerticesFlag; + fFlags &= ~kRequiresPerVertexColors_Flag; fColorArrayType = GrRenderTargetContext::ColorArrayType::kPremulGrColor; } - if (!(fPipelineNeedsLocalCoords = optimizations.readsLocalCoords())) { - fMeshes[0].fLocalCoords.reset(); + if (optimizations.readsLocalCoords()) { + fFlags |= kPipelineRequiresLocalCoords_Flag; + } else { + fFlags |= SkCanvas::kIgnoreTexCoords_VerticesFlag; + fFlags &= ~kAnyMeshHasExplicitLocalCoords; } } +sk_sp<GrGeometryProcessor> GrDrawVerticesOp::makeGP(bool* hasColorAttribute, + bool* hasLocalCoordAttribute) const { + using namespace GrDefaultGeoProcFactory; + LocalCoords::Type localCoordsType; + if (this->pipelineRequiresLocalCoords()) { + // If we have multiple view matrices we will transform the positions into device space. We + // must then also provide untransformed positions as local coords. + if (this->anyMeshHasExplicitLocalCoords() || this->hasMultipleViewMatrices()) { + *hasLocalCoordAttribute = true; + localCoordsType = LocalCoords::kHasExplicit_Type; + } else { + *hasLocalCoordAttribute = false; + localCoordsType = LocalCoords::kUsePosition_Type; + } + } else { + localCoordsType = LocalCoords::kUnused_Type; + *hasLocalCoordAttribute = false; + } + + Color color(fMeshes[0].fColor); + if (this->requiresPerVertexColors()) { + color.fType = (fColorArrayType == GrRenderTargetContext::ColorArrayType::kPremulGrColor) + ? Color::kPremulGrColorAttribute_Type + : Color::kUnpremulSkColorAttribute_Type; + *hasColorAttribute = true; + } else { + *hasColorAttribute = false; + }; + const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix; + return GrDefaultGeoProcFactory::Make(color, Coverage::kSolid_Type, localCoordsType, vm); +} + void GrDrawVerticesOp::onPrepareDraws(Target* target) const { - bool clientLocalCoords = !fMeshes[0].fLocalCoords.isEmpty(); - bool hasLocalCoordAttribute; - sk_sp<GrGeometryProcessor> gp = - make_gp(clientLocalCoords, fPipelineNeedsLocalCoords, fColorArrayType, - fMultipleViewMatrices, fMeshes[0].fViewMatrix, &hasLocalCoordAttribute); + bool hasColorAttribute; + bool hasLocalCoordsAttribute; + sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute, &hasLocalCoordsAttribute); size_t vertexStride = gp->getVertexStride(); - SkASSERT(vertexStride == - sizeof(SkPoint) + (hasLocalCoordAttribute ? sizeof(SkPoint) : 0) + sizeof(uint32_t)); + SkASSERT(vertexStride == sizeof(SkPoint) + (hasColorAttribute ? sizeof(uint32_t) : 0) + + (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0)); int instanceCount = fMeshes.count(); @@ -135,7 +180,7 @@ void GrDrawVerticesOp::onPrepareDraws(Target* target) const { int firstIndex = 0; uint16_t* indices = nullptr; - if (!fMeshes[0].fIndices.isEmpty()) { + if (this->isIndexed()) { indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex); if (!indices) { @@ -148,34 +193,39 @@ void GrDrawVerticesOp::onPrepareDraws(Target* target) const { int vertexOffset = 0; for (int i = 0; i < instanceCount; i++) { const Mesh& mesh = fMeshes[i]; - // Currently we require all meshes to either have explicit local coords or not, though it - // wouldn't be hard to allow them to mix. - SkASSERT(clientLocalCoords == !mesh.fLocalCoords.isEmpty()); if (indices) { - for (int j = 0; j < mesh.fIndices.count(); ++j, ++indexOffset) { - *(indices + indexOffset) = mesh.fIndices[j] + vertexOffset; + int indexCount = mesh.fVertices->indexCount(); + for (int j = 0; j < indexCount; ++j, ++indexOffset) { + *(indices + indexOffset) = mesh.fVertices->indices()[j] + vertexOffset; } } static constexpr size_t kColorOffset = sizeof(SkPoint); - static constexpr size_t kLocalCoordOffset = kColorOffset + sizeof(uint32_t); - - for (int j = 0; j < mesh.fPositions.count(); ++j) { - if (fMultipleViewMatrices) { - mesh.fViewMatrix.mapPoints(((SkPoint*)verts), &mesh.fPositions[j], 1); + size_t localCoordOffset = + hasColorAttribute ? kColorOffset + sizeof(uint32_t) : kColorOffset; + + int vertexCount = mesh.fVertices->vertexCount(); + const SkPoint* positions = mesh.fVertices->positions(); + const SkColor* colors = mesh.fVertices->colors(); + const SkPoint* localCoords = mesh.fVertices->texCoords(); + for (int j = 0; j < vertexCount; ++j) { + if (this->hasMultipleViewMatrices()) { + mesh.fViewMatrix.mapPoints(((SkPoint*)verts), &positions[j], 1); } else { - *((SkPoint*)verts) = mesh.fPositions[j]; + *((SkPoint*)verts) = positions[j]; } - if (mesh.fColors.isEmpty()) { - *(uint32_t*)((intptr_t)verts + kColorOffset) = mesh.fColor; - } else { - *(uint32_t*)((intptr_t)verts + kColorOffset) = mesh.fColors[j]; + if (hasColorAttribute) { + if (mesh.hasPerVertexColors()) { + *(uint32_t*)((intptr_t)verts + kColorOffset) = colors[j]; + } else { + *(uint32_t*)((intptr_t)verts + kColorOffset) = mesh.fColor; + } } - if (hasLocalCoordAttribute) { - if (clientLocalCoords) { - *(SkPoint*)((intptr_t)verts + kLocalCoordOffset) = mesh.fLocalCoords[j]; + if (hasLocalCoordsAttribute) { + if (mesh.hasExplicitLocalCoords()) { + *(SkPoint*)((intptr_t)verts + localCoordOffset) = localCoords[j]; } else { - *(SkPoint*)((intptr_t)verts + kLocalCoordOffset) = mesh.fPositions[j]; + *(SkPoint*)((intptr_t)verts + localCoordOffset) = positions[j]; } } verts = (void*)((intptr_t)verts + vertexStride); @@ -206,14 +256,7 @@ bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { return false; } - - if (fMeshes[0].fIndices.isEmpty() != that->fMeshes[0].fIndices.isEmpty()) { - return false; - } - - // This could be relaxed by using positions for the one that doesn't already have explicit - // local coordindates. - if (fMeshes[0].fLocalCoords.isEmpty() != that->fMeshes[0].fLocalCoords.isEmpty()) { + if (fMeshes[0].fVertices->isIndexed() != that->fMeshes[0].fVertices->isIndexed()) { return false; } @@ -221,22 +264,21 @@ bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { return false; } - if (fIndexCount + that->fIndexCount > SK_MaxU16) { + if (fVertexCount + that->fVertexCount > SK_MaxU16) { return false; } - if (!fVariableColor) { - if (that->fVariableColor || that->fMeshes[0].fColor != fMeshes[0].fColor) { - fVariableColor = true; - } - } + // If either op required explicit local coords or per-vertex colors the combined mesh does. Same + // with multiple view matrices. + fFlags |= that->fFlags; + if (!this->requiresPerVertexColors() && this->fMeshes[0].fColor != that->fMeshes[0].fColor) { + fFlags |= kRequiresPerVertexColors_Flag; + } // Check whether we are about to acquire a mesh with a different view matrix. - if (!fMultipleViewMatrices) { - if (that->fMultipleViewMatrices || - !fMeshes[0].fViewMatrix.cheapEqualTo(that->fMeshes[0].fViewMatrix)) { - fMultipleViewMatrices = true; - } + if (!this->hasMultipleViewMatrices() && + !this->fMeshes[0].fViewMatrix.cheapEqualTo(that->fMeshes[0].fViewMatrix)) { + fFlags |= kHasMultipleViewMatrices_Flag; } fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin()); @@ -348,11 +390,9 @@ DRAW_OP_TEST_DEFINE(VerticesOp) { SkDEBUGCODE(bool result =) bounds.setBoundsCheck(positions.begin(), vertexCount); SkASSERT(result); - viewMatrix.mapRect(&bounds); - GrColor color = GrRandomColor(random); return GrDrawVerticesOp::Make(color, type, viewMatrix, positions.begin(), vertexCount, - indices.begin(), hasIndices ? vertexCount : 0, colors.begin(), + indices.begin(), hasIndices ? indices.count() : 0, colors.begin(), texCoords.begin(), bounds, colorArrayType); } diff --git a/src/gpu/ops/GrDrawVerticesOp.h b/src/gpu/ops/GrDrawVerticesOp.h index a2560af774..1cd3334396 100644 --- a/src/gpu/ops/GrDrawVerticesOp.h +++ b/src/gpu/ops/GrDrawVerticesOp.h @@ -15,46 +15,62 @@ #include "SkMatrix.h" #include "SkRect.h" #include "SkTDArray.h" +#include "SkVertices.h" class GrOpFlushState; +class SkVertices; struct GrInitInvariantOutput; class GrDrawVerticesOp final : public GrMeshDrawOp { public: DEFINE_OP_CLASS_ID + /** + * The 'color' param is used if the 'colors' array is null. 'bounds' is the bounds of the + * 'positions' array (in local space prior to application of 'viewMatrix'). If 'indices' is null + * then 'indexCnt' must be zero and vice versa. In this case the vertices are indexed as 0, 1, + * ..., 'vertexCount' - 1. 'localCoords' are optional and if null the vertex positions are used + * as local coords. 'colorArrayType' specifies whether the colors are premul GrColors or + * unpremul SkColors. + */ static std::unique_ptr<GrDrawOp> Make(GrColor color, GrPrimitiveType primitiveType, const SkMatrix& viewMatrix, const SkPoint* positions, int vertexCount, const uint16_t* indices, int indexCount, const uint32_t* colors, const SkPoint* localCoords, const SkRect& bounds, - GrRenderTargetContext::ColorArrayType colorArrayType) { - return std::unique_ptr<GrDrawOp>(new GrDrawVerticesOp( - color, primitiveType, viewMatrix, positions, vertexCount, indices, indexCount, - colors, localCoords, bounds, colorArrayType)); - } + GrRenderTargetContext::ColorArrayType colorArrayType); + + /** + * Draw a SkVertices. The GrColor param is used if the vertices lack per-vertex color or 'flags' + * indicates that the per-vertex color should be ignored. The 'flags' options are those + * specified by SkCanvas::VerticesFlags. If the vertices lack local coords or 'flags' indicates + * that they should be ignored then the vertex positions are used as local coords. + */ + static std::unique_ptr<GrDrawOp> Make(GrColor color, sk_sp<SkVertices>, + const SkMatrix& viewMatrix, uint32_t flags); const char* name() const override { return "DrawVerticesOp"; } SkString dumpInfo() const override { SkString string; - string.appendf("PrimType: %d, VarColor: %d, VCount: %d, ICount: %d\n", fPrimitiveType, - fVariableColor, fVertexCount, fIndexCount); + string.appendf("PrimType: %d, MeshCount %d, VCount: %d, ICount: %d\n", fPrimitiveType, + fMeshes.count(), fVertexCount, fIndexCount); string.append(DumpPipelineInfo(*this->pipeline())); string.append(INHERITED::dumpInfo()); return string; } private: - GrDrawVerticesOp(GrColor color, GrPrimitiveType primitiveType, const SkMatrix& viewMatrix, - const SkPoint* positions, int vertexCount, const uint16_t* indices, - int indexCount, const uint32_t* colors, const SkPoint* localCoords, - const SkRect& bounds, GrRenderTargetContext::ColorArrayType colorArrayType); + GrDrawVerticesOp(sk_sp<SkVertices>, GrPrimitiveType, GrColor, + GrRenderTargetContext::ColorArrayType, const SkMatrix& viewMatrix, + uint32_t flags = 0); void getPipelineAnalysisInput(GrPipelineAnalysisDrawOpInput* input) const override; void applyPipelineOptimizations(const GrPipelineOptimizations&) override; void onPrepareDraws(Target*) const override; + sk_sp<GrGeometryProcessor> makeGP(bool* hasColorAttribute, bool* hasLocalCoordAttribute) const; + GrPrimitiveType primitiveType() const { return fPrimitiveType; } bool combinablePrimitive() const { return kTriangles_GrPrimitiveType == fPrimitiveType || @@ -65,20 +81,55 @@ private: bool onCombineIfPossible(GrOp* t, const GrCaps&) override; struct Mesh { - GrColor fColor; // Only used if there are no per-vertex colors - SkTDArray<SkPoint> fPositions; - SkTDArray<uint16_t> fIndices; - SkTDArray<uint32_t> fColors; - SkTDArray<SkPoint> fLocalCoords; + GrColor fColor; // Used if this->hasPerVertexColors() is false. + sk_sp<SkVertices> fVertices; SkMatrix fViewMatrix; + uint32_t fFlags; + + bool hasExplicitLocalCoords() const { + return fVertices->hasTexCoords() && !(SkCanvas::kIgnoreTexCoords_VerticesFlag & fFlags); + } + + bool hasPerVertexColors() const { + return fVertices->hasColors() && !(SkCanvas::kIgnoreColors_VerticesFlag & fFlags); + } + }; + + bool isIndexed() const { + // Consistency enforced in onCombineIfPossible. + return fMeshes[0].fVertices->isIndexed(); + } + + bool requiresPerVertexColors() const { + return SkToBool(kRequiresPerVertexColors_Flag & fFlags); + } + + bool anyMeshHasExplicitLocalCoords() const { + return SkToBool(kAnyMeshHasExplicitLocalCoords & fFlags); + } + + bool pipelineRequiresLocalCoords() const { + return SkToBool(kPipelineRequiresLocalCoords_Flag & fFlags); + } + + bool hasMultipleViewMatrices() const { + return SkToBool(kHasMultipleViewMatrices_Flag & fFlags); + } + + enum Flags { + kRequiresPerVertexColors_Flag = 0x1, + kAnyMeshHasExplicitLocalCoords = 0x2, + kPipelineRequiresLocalCoords_Flag = 0x4, + kHasMultipleViewMatrices_Flag = 0x8 + }; + // GrPrimitiveType is more expressive than fVertices.mode() so it is used instead and we ignore + // the SkVertices mode (though fPrimitiveType may have been inferred from it). GrPrimitiveType fPrimitiveType; - bool fVariableColor; + uint32_t fFlags; int fVertexCount; int fIndexCount; - bool fMultipleViewMatrices = false; - bool fPipelineNeedsLocalCoords; GrRenderTargetContext::ColorArrayType fColorArrayType; SkSTArray<1, Mesh, true> fMeshes; diff --git a/tools/debugger/SkDebugCanvas.h b/tools/debugger/SkDebugCanvas.h index 57bf99874a..d25fe40274 100644 --- a/tools/debugger/SkDebugCanvas.h +++ b/tools/debugger/SkDebugCanvas.h @@ -16,6 +16,7 @@ #include "SkPicture.h" #include "SkString.h" #include "SkTArray.h" +#include "SkVertices.h" #include "UrlDataManager.h" class GrAuditTrail; @@ -229,6 +230,10 @@ protected: const SkColor colors[], SkBlendMode, const uint16_t indices[], int indexCount, const SkPaint&) override; + void onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint, + uint32_t flags) override { + this->onDrawVerticesObjectFallback(std::move(vertices), mode, paint, flags); + } void onDrawPath(const SkPath&, const SkPaint&) override; void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override; void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, |