diff options
author | Florin Malita <fmalita@chromium.org> | 2017-02-16 22:12:41 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-02-17 03:45:02 +0000 |
commit | f614ba2ddc7e0805616bd40e104021695ff7d767 (patch) | |
tree | aa12721ce9cb3624524be7b70e09cce7bcbd43fe | |
parent | 1d2aed03983c068433387c37a0ba54c909921e07 (diff) |
Fix drawVertices() texture mapping in the presence of a local matrix
Change-Id: I6379f2e7c030d7d1e0fcb2bd6ecc7d81c8a4eec5
Reviewed-on: https://skia-review.googlesource.com/8502
Commit-Queue: Florin Malita <fmalita@chromium.org>
Reviewed-by: Mike Reed <reed@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
-rw-r--r-- | gm/vertices.cpp | 51 | ||||
-rw-r--r-- | src/core/SkDraw.cpp | 60 |
2 files changed, 91 insertions, 20 deletions
diff --git a/gm/vertices.cpp b/gm/vertices.cpp index eecd9d70a3..a8f74bface 100644 --- a/gm/vertices.cpp +++ b/gm/vertices.cpp @@ -9,19 +9,29 @@ #include "SkCanvas.h" #include "SkColorFilter.h" #include "SkGradientShader.h" +#include "SkLocalMatrixShader.h" #include "SkRandom.h" #include "SkVertices.h" static constexpr SkScalar kShaderSize = 40; -static sk_sp<SkShader> make_shader1() { +static sk_sp<SkShader> make_shader1(SkScalar shaderScale) { const SkColor colors[] = { SK_ColorRED, SK_ColorCYAN, SK_ColorGREEN, SK_ColorWHITE, SK_ColorMAGENTA, SK_ColorBLUE, SK_ColorYELLOW, }; const SkPoint pts[] = {{kShaderSize / 4, 0}, {3 * kShaderSize / 4, kShaderSize}}; + const SkMatrix localMatrix = SkMatrix::MakeScale(shaderScale, shaderScale); - return SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors), - SkShader::kMirror_TileMode); + sk_sp<SkShader> grad = SkGradientShader::MakeLinear(pts, colors, nullptr, + SK_ARRAY_COUNT(colors), + SkShader::kMirror_TileMode, 0, + &localMatrix); + // Throw in a couple of local matrix wrappers for good measure. + return shaderScale == 1 + ? grad + : sk_make_sp<SkLocalMatrixShader>( + sk_make_sp<SkLocalMatrixShader>(std::move(grad), SkMatrix::MakeTrans(-10, 0)), + SkMatrix::MakeTrans(10, 0)); } static sk_sp<SkShader> make_shader2() { @@ -44,7 +54,7 @@ static const int kMeshIndexCnt = (int)SK_ARRAY_COUNT(kMeshFan); static const int kMeshVertexCnt = 9; static void fill_mesh(SkPoint pts[kMeshVertexCnt], SkPoint texs[kMeshVertexCnt], - SkColor colors[kMeshVertexCnt]) { + SkColor colors[kMeshVertexCnt], SkScalar shaderScale) { pts[0].set(0, 0); pts[1].set(kMeshSize / 2, 3); pts[2].set(kMeshSize, 0); @@ -55,15 +65,16 @@ static void fill_mesh(SkPoint pts[kMeshVertexCnt], SkPoint texs[kMeshVertexCnt], pts[7].set(kMeshSize / 2, kMeshSize - 3); pts[8].set(kMeshSize, kMeshSize); + const auto shaderSize = kShaderSize * shaderScale; texs[0].set(0, 0); - texs[1].set(kShaderSize / 2, 0); - texs[2].set(kShaderSize, 0); - texs[3].set(0, kShaderSize / 2); - texs[4].set(kShaderSize / 2, kShaderSize / 2); - texs[5].set(kShaderSize, kShaderSize / 2); - texs[6].set(0, kShaderSize); - texs[7].set(kShaderSize / 2, kShaderSize); - texs[8].set(kShaderSize, kShaderSize); + texs[1].set(shaderSize / 2, 0); + texs[2].set(shaderSize, 0); + texs[3].set(0, shaderSize / 2); + texs[4].set(shaderSize / 2, shaderSize / 2); + texs[5].set(shaderSize, shaderSize / 2); + texs[6].set(0, shaderSize); + texs[7].set(shaderSize / 2, shaderSize); + texs[8].set(shaderSize, shaderSize); SkRandom rand; for (size_t i = 0; i < kMeshVertexCnt; ++i) { @@ -80,15 +91,17 @@ class VerticesGM : public skiagm::GM { sk_sp<SkColorFilter> fColorFilter; sk_sp<SkVertices> fVertices; bool fUseObject; + SkScalar fShaderScale; public: - VerticesGM(bool useObject) : fUseObject(useObject) {} + VerticesGM(bool useObject, SkScalar shaderScale = 1) + : fUseObject(useObject), fShaderScale(shaderScale) {} protected: void onOnceBeforeDraw() override { - fill_mesh(fPts, fTexs, fColors); - fShader1 = make_shader1(); + fill_mesh(fPts, fTexs, fColors, fShaderScale); + fShader1 = make_shader1(fShaderScale); fShader2 = make_shader2(); fColorFilter = make_color_filter(); if (fUseObject) { @@ -118,6 +131,9 @@ protected: if (fUseObject) { name.append("_object"); } + if (fShaderScale != 1) { + name.append("_scaled_shader"); + } return name; } @@ -208,12 +224,13 @@ private: DEF_GM(return new VerticesGM(true);) DEF_GM(return new VerticesGM(false);) +DEF_GM(return new VerticesGM(false, 1 / kShaderSize);) 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()); + fill_mesh(pts.get(), texs.get(), colors.get(), 1); SkTDArray<SkMatrix> matrices; matrices.push()->reset(); @@ -223,7 +240,7 @@ static void draw_batching(SkCanvas* canvas, bool useObject) { m->postScale(1.2f, .8f, kMeshSize / 2, kMeshSize / 2); m->postTranslate(0, 80); - auto shader = make_shader1(); + auto shader = make_shader1(1); // Triangle fans can't batch so we convert to regular triangles, static constexpr int kNumTris = kMeshIndexCnt - 2; diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index 4ec48952eb..4182ef3a72 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -1855,7 +1855,56 @@ void SkTriColorShader::toString(SkString* str) const { } #endif -static sk_sp<SkShader> MakeTextureShader(const VertState& state, const SkPoint verts[], +namespace { + +// Similar to SkLocalMatrixShader, but composes the local matrix with the CTM (instead +// of composing with the inherited local matrix): +// +// rec' = {rec.ctm x localMatrix, rec.localMatrix} +// +// (as opposed to rec' = {rec.ctm, rec.localMatrix x localMatrix}) +// +class SkLocalInnerMatrixShader final : public SkShader { +public: + SkLocalInnerMatrixShader(sk_sp<SkShader> proxy, const SkMatrix& localMatrix) + : INHERITED(&localMatrix) + , fProxyShader(std::move(proxy)) {} + + Factory getFactory() const override { + SkASSERT(false); + return nullptr; + } + +protected: + void flatten(SkWriteBuffer&) const override { + SkASSERT(false); + } + + Context* onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const override { + SkMatrix adjustedCTM = SkMatrix::Concat(*rec.fMatrix, this->getLocalMatrix()); + ContextRec newRec(rec); + newRec.fMatrix = &adjustedCTM; + return fProxyShader->makeContext(newRec, alloc); + } + + bool onAppendStages(SkRasterPipeline* p, SkColorSpace* cs, SkArenaAlloc* alloc, + const SkMatrix& ctm, const SkPaint& paint, + const SkMatrix* localM) const override { + // We control the shader graph ancestors, so we know there's no local matrix being + // injected before this. + SkASSERT(!localM); + + SkMatrix adjustedCTM = SkMatrix::Concat(ctm, this->getLocalMatrix()); + return fProxyShader->appendStages(p, cs, alloc, adjustedCTM, paint); + } + +private: + sk_sp<SkShader> fProxyShader; + + typedef SkShader INHERITED; +}; + +sk_sp<SkShader> MakeTextureShader(const VertState& state, const SkPoint verts[], const SkPoint texs[], const SkPaint& paint, SkColorSpace* dstColorSpace, SkArenaAlloc* alloc) { @@ -1868,9 +1917,12 @@ static sk_sp<SkShader> MakeTextureShader(const VertState& state, const SkPoint v if (p0 != p1 || p0 != p2) { // Common case (non-collapsed texture coordinates). // Map the texture to vertices using a local transform. + + // We cannot use a plain SkLocalMatrix shader, because we need the texture matrix + // to compose next to the CTM. SkMatrix localMatrix; return texture_to_matrix(state, verts, texs, &localMatrix) - ? alloc->makeSkSp<SkLocalMatrixShader>(paint.refShader(), localMatrix) + ? alloc->makeSkSp<SkLocalInnerMatrixShader>(paint.refShader(), localMatrix) : nullptr; } @@ -1901,6 +1953,8 @@ static sk_sp<SkShader> MakeTextureShader(const VertState& state, const SkPoint v return alloc->makeSkSp<SkColorShader>(SkUnPreMultiply::PMColorToColor(pmColor)); } +} // anonymous ns + void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, const SkPoint vertices[], const SkPoint textures[], const SkColor colors[], SkBlendMode bmode, @@ -1978,7 +2032,7 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, // static constexpr size_t kAllocSize = sizeof(SkAutoBlitterChoose) + sizeof(SkComposeShader) + - SkTMax(sizeof(SkLocalMatrixShader), sizeof(SkColorShader)); + SkTMax(sizeof(SkLocalInnerMatrixShader), sizeof(SkColorShader)); char allocBuffer[kAllocSize]; SkArenaAlloc alloc(allocBuffer); |