aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Mike Reed <reed@google.com>2017-05-15 09:29:18 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-05-15 13:51:25 +0000
commit787a16dd9e03f3971898131dd778206c8cb9a0df (patch)
treebf01f704822356e12ce62d24512ab98778976f14
parentdedac85b4f08546e92143d96c13b753cb1b80e23 (diff)
move impl for drawvertices into separate file
expect to refactor the impl, so this just makes that easier (plus SkDraw.cpp was just too big) Bug: skia: Change-Id: I22c07d37429195363d9a76e56a1dca915f9c2d57 Reviewed-on: https://skia-review.googlesource.com/16863 Commit-Queue: Mike Reed <reed@google.com> Reviewed-by: Florin Malita <fmalita@chromium.org>
-rw-r--r--gn/core.gni1
-rw-r--r--src/core/SkAutoBlitterChoose.h46
-rw-r--r--src/core/SkDraw.cpp513
-rw-r--r--src/core/SkDraw_vertices.cpp479
4 files changed, 532 insertions, 507 deletions
diff --git a/gn/core.gni b/gn/core.gni
index da92020cfc..1d88821f7d 100644
--- a/gn/core.gni
+++ b/gn/core.gni
@@ -121,6 +121,7 @@ skia_core_sources = [
"$_src/core/SkDither.h",
"$_src/core/SkDocument.cpp",
"$_src/core/SkDraw.cpp",
+ "$_src/core/SkDraw_vertices.cpp",
"$_src/core/SkDraw.h",
"$_src/core/SkDrawable.cpp",
"$_src/core/SkDrawLooper.cpp",
diff --git a/src/core/SkAutoBlitterChoose.h b/src/core/SkAutoBlitterChoose.h
new file mode 100644
index 0000000000..460e30d076
--- /dev/null
+++ b/src/core/SkAutoBlitterChoose.h
@@ -0,0 +1,46 @@
+/*
+ * 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 SkAutoBlitterChoose_DEFINED
+#define SkAutoBlitterChoose_DEFINED
+
+#include "SkArenaAlloc.h"
+#include "SkBlitter.h"
+
+class SkMatrix;
+class SkPaint;
+class SkPixmap;
+
+class SkAutoBlitterChoose : SkNoncopyable {
+public:
+ SkAutoBlitterChoose() {
+ fBlitter = nullptr;
+ }
+ SkAutoBlitterChoose(const SkPixmap& dst, const SkMatrix& matrix,
+ const SkPaint& paint, bool drawCoverage = false) {
+ fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAlloc, drawCoverage);
+ }
+
+ SkBlitter* operator->() { return fBlitter; }
+ SkBlitter* get() const { return fBlitter; }
+
+ void choose(const SkPixmap& dst, const SkMatrix& matrix,
+ const SkPaint& paint, bool drawCoverage = false) {
+ SkASSERT(!fBlitter);
+ fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAlloc, drawCoverage);
+ }
+
+private:
+ // Owned by fAlloc, which will handle the delete.
+ SkBlitter* fBlitter;
+
+ char fStorage[kSkBlitterContextSize];
+ SkArenaAlloc fAlloc{fStorage};
+};
+#define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose)
+
+#endif
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index cbb9d26d14..8245d46093 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -4,23 +4,23 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
-#define __STDC_LIMIT_MACROS
-#include "SkDraw.h"
+#define __STDC_LIMIT_MACROS
#include "SkArenaAlloc.h"
+#include "SkAutoBlitterChoose.h"
#include "SkBlendModePriv.h"
#include "SkBlitter.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
-#include "SkColorShader.h"
#include "SkDevice.h"
#include "SkDeviceLooper.h"
+#include "SkDraw.h"
+#include "SkDrawProcs.h"
#include "SkFindAndPlaceGlyph.h"
-#include "SkFixed.h"
-#include "SkLocalMatrixShader.h"
#include "SkMaskFilter.h"
#include "SkMatrix.h"
+#include "SkMatrixUtils.h"
#include "SkPaint.h"
#include "SkPathEffect.h"
#include "SkRasterClip.h"
@@ -34,50 +34,12 @@
#include "SkTemplates.h"
#include "SkTextMapStateProc.h"
#include "SkTLazy.h"
-#include "SkUnPreMultiply.h"
#include "SkUtils.h"
-#include "SkVertState.h"
-
-#include "SkBitmapProcShader.h"
-#include "SkDrawProcs.h"
-#include "SkMatrixUtils.h"
-
-//#define TRACE_BITMAP_DRAWS
// Helper function to fix code gen bug on ARM64.
// See SkFindAndPlaceGlyph.h for more details.
void FixGCC49Arm64Bug(int v) { }
-/** Helper for allocating small blitters on the stack.
- */
-class SkAutoBlitterChoose : SkNoncopyable {
-public:
- SkAutoBlitterChoose() {
- fBlitter = nullptr;
- }
- SkAutoBlitterChoose(const SkPixmap& dst, const SkMatrix& matrix,
- const SkPaint& paint, bool drawCoverage = false) {
- fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAlloc, drawCoverage);
- }
-
- SkBlitter* operator->() { return fBlitter; }
- SkBlitter* get() const { return fBlitter; }
-
- void choose(const SkPixmap& dst, const SkMatrix& matrix,
- const SkPaint& paint, bool drawCoverage = false) {
- SkASSERT(!fBlitter);
- fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAlloc, drawCoverage);
- }
-
-private:
- // Owned by fAlloc, which will handle the delete.
- SkBlitter* fBlitter;
-
- char fStorage[kSkBlitterContextSize];
- SkArenaAlloc fAlloc{fStorage};
-};
-#define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose)
-
static SkPaint make_paint_with_image(
const SkPaint& origPaint, const SkBitmap& bitmap, SkMatrix* matrix = nullptr) {
SkPaint paint(origPaint);
@@ -1670,470 +1632,7 @@ void SkDraw::drawPosText(const char text[], size_t byteLength, const SkScalar po
#pragma warning ( pop )
#endif
-///////////////////////////////////////////////////////////////////////////////
-
-struct Matrix43 {
- float fMat[12]; // column major
-
- Sk4f map(float x, float y) const {
- return Sk4f::Load(&fMat[0]) * x + Sk4f::Load(&fMat[4]) * y + Sk4f::Load(&fMat[8]);
- }
-
- void setConcat(const Matrix43& a, const SkMatrix& b) {
- fMat[ 0] = a.dot(0, b.getScaleX(), b.getSkewY());
- fMat[ 1] = a.dot(1, b.getScaleX(), b.getSkewY());
- fMat[ 2] = a.dot(2, b.getScaleX(), b.getSkewY());
- fMat[ 3] = a.dot(3, b.getScaleX(), b.getSkewY());
-
- fMat[ 4] = a.dot(0, b.getSkewX(), b.getScaleY());
- fMat[ 5] = a.dot(1, b.getSkewX(), b.getScaleY());
- fMat[ 6] = a.dot(2, b.getSkewX(), b.getScaleY());
- fMat[ 7] = a.dot(3, b.getSkewX(), b.getScaleY());
-
- fMat[ 8] = a.dot(0, b.getTranslateX(), b.getTranslateY()) + a.fMat[ 8];
- fMat[ 9] = a.dot(1, b.getTranslateX(), b.getTranslateY()) + a.fMat[ 9];
- fMat[10] = a.dot(2, b.getTranslateX(), b.getTranslateY()) + a.fMat[10];
- fMat[11] = a.dot(3, b.getTranslateX(), b.getTranslateY()) + a.fMat[11];
- }
-
-private:
- float dot(int index, float x, float y) const {
- return fMat[index + 0] * x + fMat[index + 4] * y;
- }
-};
-
-static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) {
- return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine;
-}
-
-static bool texture_to_matrix(const VertState& state, const SkPoint verts[],
- const SkPoint texs[], SkMatrix* matrix) {
- SkPoint src[3], dst[3];
-
- src[0] = texs[state.f0];
- src[1] = texs[state.f1];
- src[2] = texs[state.f2];
- dst[0] = verts[state.f0];
- dst[1] = verts[state.f1];
- dst[2] = verts[state.f2];
- return matrix->setPolyToPoly(src, dst, 3);
-}
-
-class SkTriColorShader : public SkShader {
-public:
- SkTriColorShader();
-
- class TriColorShaderContext : public SkShader::Context {
- public:
- TriColorShaderContext(const SkTriColorShader& shader, const ContextRec&);
- ~TriColorShaderContext() override;
- void shadeSpan(int x, int y, SkPMColor dstC[], int count) override;
- void shadeSpan4f(int x, int y, SkPM4f dstC[], int count) override;
-
- private:
- bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
-
- SkMatrix fDstToUnit;
- SkPMColor fColors[3];
- bool fSetup;
-
- Matrix43 fM43;
-
- typedef SkShader::Context INHERITED;
- };
-
- struct TriColorShaderData {
- const SkPoint* pts;
- const SkColor* colors;
- const VertState *state;
- };
-
- SK_TO_STRING_OVERRIDE()
-
- // For serialization. This will never be called.
- Factory getFactory() const override { sk_throw(); return nullptr; }
-
- // Supply setup data to context from drawing setup
- void bindSetupData(TriColorShaderData* setupData) { fSetupData = setupData; }
-
- // Take the setup data from context when needed.
- TriColorShaderData* takeSetupData() {
- TriColorShaderData *data = fSetupData;
- fSetupData = NULL;
- return data;
- }
-
-protected:
- Context* onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const override {
- return alloc->make<TriColorShaderContext>(*this, rec);
- }
-
-private:
- TriColorShaderData *fSetupData;
-
- typedef SkShader INHERITED;
-};
-
-bool SkTriColorShader::TriColorShaderContext::setup(const SkPoint pts[], const SkColor colors[],
- int index0, int index1, int index2) {
-
- fColors[0] = SkPreMultiplyColor(colors[index0]);
- fColors[1] = SkPreMultiplyColor(colors[index1]);
- fColors[2] = SkPreMultiplyColor(colors[index2]);
-
- SkMatrix m, im;
- m.reset();
- m.set(0, pts[index1].fX - pts[index0].fX);
- m.set(1, pts[index2].fX - pts[index0].fX);
- m.set(2, pts[index0].fX);
- m.set(3, pts[index1].fY - pts[index0].fY);
- m.set(4, pts[index2].fY - pts[index0].fY);
- m.set(5, pts[index0].fY);
- if (!m.invert(&im)) {
- return false;
- }
- // We can't call getTotalInverse(), because we explicitly don't want to look at the localmatrix
- // as our interators are intrinsically tied to the vertices, and nothing else.
- SkMatrix ctmInv;
- if (!this->getCTM().invert(&ctmInv)) {
- return false;
- }
- // TODO replace INV(m) * INV(ctm) with INV(ctm * m)
- fDstToUnit.setConcat(im, ctmInv);
-
- Sk4f alpha(this->getPaintAlpha() * (1.0f / 255)),
- c0 = SkPM4f::FromPMColor(fColors[0]).to4f() * alpha,
- c1 = SkPM4f::FromPMColor(fColors[1]).to4f() * alpha,
- c2 = SkPM4f::FromPMColor(fColors[2]).to4f() * alpha;
-
- Matrix43 colorm;
- (c1 - c0).store(&colorm.fMat[0]);
- (c2 - c0).store(&colorm.fMat[4]);
- c0.store(&colorm.fMat[8]);
- fM43.setConcat(colorm, fDstToUnit);
-
- return true;
-}
-
-#include "SkColorPriv.h"
-#include "SkComposeShader.h"
-
-static int ScalarTo256(SkScalar v) {
- return static_cast<int>(SkScalarPin(v, 0, 1) * 256 + 0.5);
-}
-
-SkTriColorShader::SkTriColorShader()
- : INHERITED(NULL)
- , fSetupData(NULL) {}
-
-SkTriColorShader::TriColorShaderContext::TriColorShaderContext(const SkTriColorShader& shader,
- const ContextRec& rec)
- : INHERITED(shader, rec)
- , fSetup(false) {}
-
-SkTriColorShader::TriColorShaderContext::~TriColorShaderContext() {}
-
-void SkTriColorShader::TriColorShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
- SkTriColorShader* parent = static_cast<SkTriColorShader*>(const_cast<SkShader*>(&fShader));
- TriColorShaderData* set = parent->takeSetupData();
- if (set) {
- fSetup = setup(set->pts, set->colors, set->state->f0, set->state->f1, set->state->f2);
- }
-
- if (!fSetup) {
- // Invalid matrices. Not checked before so no need to assert.
- return;
- }
-
- const int alphaScale = Sk255To256(this->getPaintAlpha());
-
- SkPoint src;
-
- fDstToUnit.mapXY(SkIntToScalar(x) + 0.5, SkIntToScalar(y) + 0.5, &src);
- for (int i = 0; i < count; i++) {
- int scale1 = ScalarTo256(src.fX);
- int scale2 = ScalarTo256(src.fY);
- int scale0 = 256 - scale1 - scale2;
- if (scale0 < 0) {
- if (scale1 > scale2) {
- scale2 = 256 - scale1;
- } else {
- scale1 = 256 - scale2;
- }
- scale0 = 0;
- }
-
- if (256 != alphaScale) {
- scale0 = SkAlphaMul(scale0, alphaScale);
- scale1 = SkAlphaMul(scale1, alphaScale);
- scale2 = SkAlphaMul(scale2, alphaScale);
- }
-
- dstC[i] = SkAlphaMulQ(fColors[0], scale0) +
- SkAlphaMulQ(fColors[1], scale1) +
- SkAlphaMulQ(fColors[2], scale2);
-
- src.fX += fDstToUnit.getScaleX();
- src.fY += fDstToUnit.getSkewY();
- }
-}
-
-void SkTriColorShader::TriColorShaderContext::shadeSpan4f(int x, int y, SkPM4f dstC[], int count) {
- SkTriColorShader* parent = static_cast<SkTriColorShader*>(const_cast<SkShader*>(&fShader));
- TriColorShaderData* set = parent->takeSetupData();
- if (set) {
- fSetup = setup(set->pts, set->colors, set->state->f0, set->state->f1, set->state->f2);
- }
-
- if (!fSetup) {
- // Invalid matrices. Not checked before so no need to assert.
- return;
- }
-
- Sk4f c = fM43.map(SkIntToScalar(x) + 0.5, SkIntToScalar(y) + 0.5),
- dc = Sk4f::Load(&fM43.fMat[0]),
- zero(0.0f),
- one(1.0f);
-
- for (int i = 0; i < count; i++) {
- // We don't expect to be wildly out of 0...1, but we pin just because of minor
- // numerical imprecision.
- Sk4f::Min(Sk4f::Max(c, zero), Sk4f::Min(c[3], one)).store(dstC + i);
- c += dc;
- }
-}
-
-#ifndef SK_IGNORE_TO_STRING
-void SkTriColorShader::toString(SkString* str) const {
- str->append("SkTriColorShader: (");
-
- this->INHERITED::toString(str);
-
- str->append(")");
-}
-#endif
-
-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) {
- SkASSERT(paint.getShader());
-
- const auto& p0 = texs[state.f0],
- p1 = texs[state.f1],
- p2 = texs[state.f2];
-
- 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<SkLocalInnerMatrixShader>(paint.refShader(), localMatrix)
- : nullptr;
- }
-
- // Collapsed texture coordinates special case.
- // The texture is a solid color, sampled at the given point.
- SkMatrix shaderInvLocalMatrix;
- SkAssertResult(paint.getShader()->getLocalMatrix().invert(&shaderInvLocalMatrix));
-
- const auto sample = SkPoint::Make(0.5f, 0.5f);
- const auto mappedSample = shaderInvLocalMatrix.mapXY(sample.x(), sample.y()),
- mappedPoint = shaderInvLocalMatrix.mapXY(p0.x(), p0.y());
- const auto localMatrix = SkMatrix::MakeTrans(mappedSample.x() - mappedPoint.x(),
- mappedSample.y() - mappedPoint.y());
-
- SkShader::ContextRec rec(paint, SkMatrix::I(), &localMatrix,
- SkShader::ContextRec::kPMColor_DstType, dstColorSpace);
- auto* ctx = paint.getShader()->makeContext(rec, alloc);
- if (!ctx) {
- return nullptr;
- }
-
- SkPMColor pmColor;
- ctx->shadeSpan(SkScalarFloorToInt(sample.x()), SkScalarFloorToInt(sample.y()), &pmColor, 1);
-
- // no need to keep this temp context around.
- alloc->reset();
-
- return alloc->makeSkSp<SkColorShader>(SkUnPreMultiply::PMColorToColor(pmColor));
-}
-
-} // anonymous ns
-
-void SkDraw::drawVertices(SkVertices::VertexMode vmode, int count,
- const SkPoint vertices[], const SkPoint textures[],
- const SkColor colors[], SkBlendMode bmode,
- const uint16_t indices[], int indexCount,
- const SkPaint& paint) const {
- SkASSERT(0 == count || vertices);
-
- // abort early if there is nothing to draw
- if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) {
- return;
- }
-
- // transform out vertices into device coordinates
- SkAutoSTMalloc<16, SkPoint> storage(count);
- SkPoint* devVerts = storage.get();
- fMatrix->mapPoints(devVerts, vertices, count);
-
- /*
- We can draw the vertices in 1 of 4 ways:
-
- - solid color (no shader/texture[], no colors[])
- - just colors (no shader/texture[], has colors[])
- - just texture (has shader/texture[], no colors[])
- - colors * texture (has shader/texture[], has colors[])
-
- Thus for texture drawing, we need both texture[] and a shader.
- */
-
- auto triShader = sk_make_sp<SkTriColorShader>();
- SkPaint p(paint);
-
- SkShader* shader = p.getShader();
- if (nullptr == shader) {
- // if we have no shader, we ignore the texture coordinates
- textures = nullptr;
- } else if (nullptr == textures) {
- // if we don't have texture coordinates, ignore the shader
- p.setShader(nullptr);
- shader = nullptr;
- }
-
- // setup the custom shader (if needed)
- if (colors) {
- if (nullptr == textures) {
- // just colors (no texture)
- p.setShader(triShader);
- } else {
- // colors * texture
- SkASSERT(shader);
- p.setShader(SkShader::MakeComposeShader(triShader, sk_ref_sp(shader), bmode));
- }
- }
-
- SkAutoBlitterChoose blitter(fDst, *fMatrix, p);
- // Abort early if we failed to create a shader context.
- if (blitter->isNullBlitter()) {
- return;
- }
-
- // setup our state and function pointer for iterating triangles
- VertState state(count, indices, indexCount);
- VertState::Proc vertProc = state.chooseProc(vmode);
-
- if (textures || colors) {
- SkTriColorShader::TriColorShaderData verticesSetup = { vertices, colors, &state };
-
- while (vertProc(&state)) {
- auto* blitterPtr = blitter.get();
-
- // We're going to allocate at most
- //
- // * one SkLocalMatrixShader OR one SkColorShader
- // * one SkComposeShader
- // * one SkAutoBlitterChoose
- //
- static constexpr size_t kAllocSize =
- sizeof(SkAutoBlitterChoose) + sizeof(SkComposeShader) +
- SkTMax(sizeof(SkLocalInnerMatrixShader), sizeof(SkColorShader));
- char allocBuffer[kAllocSize];
- SkArenaAlloc alloc(allocBuffer);
-
- if (textures) {
- sk_sp<SkShader> texShader = MakeTextureShader(state, vertices, textures, paint,
- fDst.colorSpace(), &alloc);
- if (texShader) {
- SkPaint localPaint(p);
- localPaint.setShader(colors
- ? alloc.makeSkSp<SkComposeShader>(triShader, std::move(texShader), bmode)
- : std::move(texShader));
-
- blitterPtr = alloc.make<SkAutoBlitterChoose>(fDst, *fMatrix, localPaint)->get();
- if (blitterPtr->isNullBlitter()) {
- continue;
- }
- }
- }
- if (colors) {
- triShader->bindSetupData(&verticesSetup);
- }
-
- SkPoint tmp[] = {
- devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
- };
- SkScan::FillTriangle(tmp, *fRC, blitterPtr);
- triShader->bindSetupData(nullptr);
- }
- } else {
- // no colors[] and no texture, stroke hairlines with paint's color.
- SkScan::HairRCProc hairProc = ChooseHairProc(paint.isAntiAlias());
- const SkRasterClip& clip = *fRC;
- while (vertProc(&state)) {
- SkPoint array[] = {
- devVerts[state.f0], devVerts[state.f1], devVerts[state.f2], devVerts[state.f0]
- };
- hairProc(array, 4, clip, blitter.get());
- }
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG
diff --git a/src/core/SkDraw_vertices.cpp b/src/core/SkDraw_vertices.cpp
new file mode 100644
index 0000000000..dcf8d585ea
--- /dev/null
+++ b/src/core/SkDraw_vertices.cpp
@@ -0,0 +1,479 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkArenaAlloc.h"
+#include "SkAutoBlitterChoose.h"
+#include "SkColorShader.h"
+#include "SkDraw.h"
+#include "SkNx.h"
+#include "SkPM4f.h"
+#include "SkRasterClip.h"
+#include "SkScan.h"
+#include "SkShader.h"
+#include "SkString.h"
+#include "SkVertState.h"
+
+struct Matrix43 {
+ float fMat[12]; // column major
+
+ Sk4f map(float x, float y) const {
+ return Sk4f::Load(&fMat[0]) * x + Sk4f::Load(&fMat[4]) * y + Sk4f::Load(&fMat[8]);
+ }
+
+ void setConcat(const Matrix43& a, const SkMatrix& b) {
+ fMat[ 0] = a.dot(0, b.getScaleX(), b.getSkewY());
+ fMat[ 1] = a.dot(1, b.getScaleX(), b.getSkewY());
+ fMat[ 2] = a.dot(2, b.getScaleX(), b.getSkewY());
+ fMat[ 3] = a.dot(3, b.getScaleX(), b.getSkewY());
+
+ fMat[ 4] = a.dot(0, b.getSkewX(), b.getScaleY());
+ fMat[ 5] = a.dot(1, b.getSkewX(), b.getScaleY());
+ fMat[ 6] = a.dot(2, b.getSkewX(), b.getScaleY());
+ fMat[ 7] = a.dot(3, b.getSkewX(), b.getScaleY());
+
+ fMat[ 8] = a.dot(0, b.getTranslateX(), b.getTranslateY()) + a.fMat[ 8];
+ fMat[ 9] = a.dot(1, b.getTranslateX(), b.getTranslateY()) + a.fMat[ 9];
+ fMat[10] = a.dot(2, b.getTranslateX(), b.getTranslateY()) + a.fMat[10];
+ fMat[11] = a.dot(3, b.getTranslateX(), b.getTranslateY()) + a.fMat[11];
+ }
+
+private:
+ float dot(int index, float x, float y) const {
+ return fMat[index + 0] * x + fMat[index + 4] * y;
+ }
+};
+
+static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) {
+ return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine;
+}
+
+static bool texture_to_matrix(const VertState& state, const SkPoint verts[],
+ const SkPoint texs[], SkMatrix* matrix) {
+ SkPoint src[3], dst[3];
+
+ src[0] = texs[state.f0];
+ src[1] = texs[state.f1];
+ src[2] = texs[state.f2];
+ dst[0] = verts[state.f0];
+ dst[1] = verts[state.f1];
+ dst[2] = verts[state.f2];
+ return matrix->setPolyToPoly(src, dst, 3);
+}
+
+class SkTriColorShader : public SkShader {
+public:
+ SkTriColorShader();
+
+ class TriColorShaderContext : public SkShader::Context {
+ public:
+ TriColorShaderContext(const SkTriColorShader& shader, const ContextRec&);
+ ~TriColorShaderContext() override;
+ void shadeSpan(int x, int y, SkPMColor dstC[], int count) override;
+ void shadeSpan4f(int x, int y, SkPM4f dstC[], int count) override;
+
+ private:
+ bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
+
+ SkMatrix fDstToUnit;
+ SkPMColor fColors[3];
+ bool fSetup;
+
+ Matrix43 fM43;
+
+ typedef SkShader::Context INHERITED;
+ };
+
+ struct TriColorShaderData {
+ const SkPoint* pts;
+ const SkColor* colors;
+ const VertState *state;
+ };
+
+ SK_TO_STRING_OVERRIDE()
+
+ // For serialization. This will never be called.
+ Factory getFactory() const override { sk_throw(); return nullptr; }
+
+ // Supply setup data to context from drawing setup
+ void bindSetupData(TriColorShaderData* setupData) { fSetupData = setupData; }
+
+ // Take the setup data from context when needed.
+ TriColorShaderData* takeSetupData() {
+ TriColorShaderData *data = fSetupData;
+ fSetupData = NULL;
+ return data;
+ }
+
+protected:
+ Context* onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const override {
+ return alloc->make<TriColorShaderContext>(*this, rec);
+ }
+
+private:
+ TriColorShaderData *fSetupData;
+
+ typedef SkShader INHERITED;
+};
+
+bool SkTriColorShader::TriColorShaderContext::setup(const SkPoint pts[], const SkColor colors[],
+ int index0, int index1, int index2) {
+
+ fColors[0] = SkPreMultiplyColor(colors[index0]);
+ fColors[1] = SkPreMultiplyColor(colors[index1]);
+ fColors[2] = SkPreMultiplyColor(colors[index2]);
+
+ SkMatrix m, im;
+ m.reset();
+ m.set(0, pts[index1].fX - pts[index0].fX);
+ m.set(1, pts[index2].fX - pts[index0].fX);
+ m.set(2, pts[index0].fX);
+ m.set(3, pts[index1].fY - pts[index0].fY);
+ m.set(4, pts[index2].fY - pts[index0].fY);
+ m.set(5, pts[index0].fY);
+ if (!m.invert(&im)) {
+ return false;
+ }
+ // We can't call getTotalInverse(), because we explicitly don't want to look at the localmatrix
+ // as our interators are intrinsically tied to the vertices, and nothing else.
+ SkMatrix ctmInv;
+ if (!this->getCTM().invert(&ctmInv)) {
+ return false;
+ }
+ // TODO replace INV(m) * INV(ctm) with INV(ctm * m)
+ fDstToUnit.setConcat(im, ctmInv);
+
+ Sk4f alpha(this->getPaintAlpha() * (1.0f / 255)),
+ c0 = SkPM4f::FromPMColor(fColors[0]).to4f() * alpha,
+ c1 = SkPM4f::FromPMColor(fColors[1]).to4f() * alpha,
+ c2 = SkPM4f::FromPMColor(fColors[2]).to4f() * alpha;
+
+ Matrix43 colorm;
+ (c1 - c0).store(&colorm.fMat[0]);
+ (c2 - c0).store(&colorm.fMat[4]);
+ c0.store(&colorm.fMat[8]);
+ fM43.setConcat(colorm, fDstToUnit);
+
+ return true;
+}
+
+#include "SkColorPriv.h"
+#include "SkComposeShader.h"
+
+static int ScalarTo256(SkScalar v) {
+ return static_cast<int>(SkScalarPin(v, 0, 1) * 256 + 0.5);
+}
+
+SkTriColorShader::SkTriColorShader()
+: INHERITED(NULL)
+, fSetupData(NULL) {}
+
+SkTriColorShader::TriColorShaderContext::TriColorShaderContext(const SkTriColorShader& shader,
+ const ContextRec& rec)
+: INHERITED(shader, rec)
+, fSetup(false) {}
+
+SkTriColorShader::TriColorShaderContext::~TriColorShaderContext() {}
+
+void SkTriColorShader::TriColorShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
+ SkTriColorShader* parent = static_cast<SkTriColorShader*>(const_cast<SkShader*>(&fShader));
+ TriColorShaderData* set = parent->takeSetupData();
+ if (set) {
+ fSetup = setup(set->pts, set->colors, set->state->f0, set->state->f1, set->state->f2);
+ }
+
+ if (!fSetup) {
+ // Invalid matrices. Not checked before so no need to assert.
+ return;
+ }
+
+ const int alphaScale = Sk255To256(this->getPaintAlpha());
+
+ SkPoint src;
+
+ fDstToUnit.mapXY(SkIntToScalar(x) + 0.5, SkIntToScalar(y) + 0.5, &src);
+ for (int i = 0; i < count; i++) {
+ int scale1 = ScalarTo256(src.fX);
+ int scale2 = ScalarTo256(src.fY);
+ int scale0 = 256 - scale1 - scale2;
+ if (scale0 < 0) {
+ if (scale1 > scale2) {
+ scale2 = 256 - scale1;
+ } else {
+ scale1 = 256 - scale2;
+ }
+ scale0 = 0;
+ }
+
+ if (256 != alphaScale) {
+ scale0 = SkAlphaMul(scale0, alphaScale);
+ scale1 = SkAlphaMul(scale1, alphaScale);
+ scale2 = SkAlphaMul(scale2, alphaScale);
+ }
+
+ dstC[i] = SkAlphaMulQ(fColors[0], scale0) +
+ SkAlphaMulQ(fColors[1], scale1) +
+ SkAlphaMulQ(fColors[2], scale2);
+
+ src.fX += fDstToUnit.getScaleX();
+ src.fY += fDstToUnit.getSkewY();
+ }
+}
+
+void SkTriColorShader::TriColorShaderContext::shadeSpan4f(int x, int y, SkPM4f dstC[], int count) {
+ SkTriColorShader* parent = static_cast<SkTriColorShader*>(const_cast<SkShader*>(&fShader));
+ TriColorShaderData* set = parent->takeSetupData();
+ if (set) {
+ fSetup = setup(set->pts, set->colors, set->state->f0, set->state->f1, set->state->f2);
+ }
+
+ if (!fSetup) {
+ // Invalid matrices. Not checked before so no need to assert.
+ return;
+ }
+
+ Sk4f c = fM43.map(SkIntToScalar(x) + 0.5, SkIntToScalar(y) + 0.5),
+ dc = Sk4f::Load(&fM43.fMat[0]),
+ zero(0.0f),
+ one(1.0f);
+
+ for (int i = 0; i < count; i++) {
+ // We don't expect to be wildly out of 0...1, but we pin just because of minor
+ // numerical imprecision.
+ Sk4f::Min(Sk4f::Max(c, zero), Sk4f::Min(c[3], one)).store(dstC + i);
+ c += dc;
+ }
+}
+
+#ifndef SK_IGNORE_TO_STRING
+void SkTriColorShader::toString(SkString* str) const {
+ str->append("SkTriColorShader: (");
+
+ this->INHERITED::toString(str);
+
+ str->append(")");
+}
+#endif
+
+
+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) {
+ SkASSERT(paint.getShader());
+
+ const auto& p0 = texs[state.f0],
+ p1 = texs[state.f1],
+ p2 = texs[state.f2];
+
+ 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<SkLocalInnerMatrixShader>(paint.refShader(), localMatrix)
+ : nullptr;
+ }
+
+ // Collapsed texture coordinates special case.
+ // The texture is a solid color, sampled at the given point.
+ SkMatrix shaderInvLocalMatrix;
+ SkAssertResult(paint.getShader()->getLocalMatrix().invert(&shaderInvLocalMatrix));
+
+ const auto sample = SkPoint::Make(0.5f, 0.5f);
+ const auto mappedSample = shaderInvLocalMatrix.mapXY(sample.x(), sample.y()),
+ mappedPoint = shaderInvLocalMatrix.mapXY(p0.x(), p0.y());
+ const auto localMatrix = SkMatrix::MakeTrans(mappedSample.x() - mappedPoint.x(),
+ mappedSample.y() - mappedPoint.y());
+
+ SkShader::ContextRec rec(paint, SkMatrix::I(), &localMatrix,
+ SkShader::ContextRec::kPMColor_DstType, dstColorSpace);
+ auto* ctx = paint.getShader()->makeContext(rec, alloc);
+ if (!ctx) {
+ return nullptr;
+ }
+
+ SkPMColor pmColor;
+ ctx->shadeSpan(SkScalarFloorToInt(sample.x()), SkScalarFloorToInt(sample.y()), &pmColor, 1);
+
+ // no need to keep this temp context around.
+ alloc->reset();
+
+ return alloc->makeSkSp<SkColorShader>(SkUnPreMultiply::PMColorToColor(pmColor));
+ }
+
+} // anonymous ns
+
+void SkDraw::drawVertices(SkVertices::VertexMode vmode, int count,
+ const SkPoint vertices[], const SkPoint textures[],
+ const SkColor colors[], SkBlendMode bmode,
+ const uint16_t indices[], int indexCount,
+ const SkPaint& paint) const {
+ SkASSERT(0 == count || vertices);
+
+ // abort early if there is nothing to draw
+ if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) {
+ return;
+ }
+
+ // transform out vertices into device coordinates
+ SkAutoSTMalloc<16, SkPoint> storage(count);
+ SkPoint* devVerts = storage.get();
+ fMatrix->mapPoints(devVerts, vertices, count);
+
+ /*
+ We can draw the vertices in 1 of 4 ways:
+
+ - solid color (no shader/texture[], no colors[])
+ - just colors (no shader/texture[], has colors[])
+ - just texture (has shader/texture[], no colors[])
+ - colors * texture (has shader/texture[], has colors[])
+
+ Thus for texture drawing, we need both texture[] and a shader.
+ */
+
+ auto triShader = sk_make_sp<SkTriColorShader>();
+ SkPaint p(paint);
+
+ SkShader* shader = p.getShader();
+ if (nullptr == shader) {
+ // if we have no shader, we ignore the texture coordinates
+ textures = nullptr;
+ } else if (nullptr == textures) {
+ // if we don't have texture coordinates, ignore the shader
+ p.setShader(nullptr);
+ shader = nullptr;
+ }
+
+ // setup the custom shader (if needed)
+ if (colors) {
+ if (nullptr == textures) {
+ // just colors (no texture)
+ p.setShader(triShader);
+ } else {
+ // colors * texture
+ SkASSERT(shader);
+ p.setShader(SkShader::MakeComposeShader(triShader, sk_ref_sp(shader), bmode));
+ }
+ }
+
+ SkAutoBlitterChoose blitter(fDst, *fMatrix, p);
+ // Abort early if we failed to create a shader context.
+ if (blitter->isNullBlitter()) {
+ return;
+ }
+
+ // setup our state and function pointer for iterating triangles
+ VertState state(count, indices, indexCount);
+ VertState::Proc vertProc = state.chooseProc(vmode);
+
+ if (textures || colors) {
+ SkTriColorShader::TriColorShaderData verticesSetup = { vertices, colors, &state };
+
+ while (vertProc(&state)) {
+ auto* blitterPtr = blitter.get();
+
+ // We're going to allocate at most
+ //
+ // * one SkLocalMatrixShader OR one SkColorShader
+ // * one SkComposeShader
+ // * one SkAutoBlitterChoose
+ //
+ static constexpr size_t kAllocSize =
+ sizeof(SkAutoBlitterChoose) + sizeof(SkComposeShader) +
+ SkTMax(sizeof(SkLocalInnerMatrixShader), sizeof(SkColorShader));
+ char allocBuffer[kAllocSize];
+ SkArenaAlloc alloc(allocBuffer);
+
+ if (textures) {
+ sk_sp<SkShader> texShader = MakeTextureShader(state, vertices, textures, paint,
+ fDst.colorSpace(), &alloc);
+ if (texShader) {
+ SkPaint localPaint(p);
+ localPaint.setShader(colors
+ ? alloc.makeSkSp<SkComposeShader>(triShader, std::move(texShader), bmode)
+ : std::move(texShader));
+
+ blitterPtr = alloc.make<SkAutoBlitterChoose>(fDst, *fMatrix, localPaint)->get();
+ if (blitterPtr->isNullBlitter()) {
+ continue;
+ }
+ }
+ }
+ if (colors) {
+ triShader->bindSetupData(&verticesSetup);
+ }
+
+ SkPoint tmp[] = {
+ devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
+ };
+ SkScan::FillTriangle(tmp, *fRC, blitterPtr);
+ triShader->bindSetupData(nullptr);
+ }
+ } else {
+ // no colors[] and no texture, stroke hairlines with paint's color.
+ SkScan::HairRCProc hairProc = ChooseHairProc(paint.isAntiAlias());
+ const SkRasterClip& clip = *fRC;
+ while (vertProc(&state)) {
+ SkPoint array[] = {
+ devVerts[state.f0], devVerts[state.f1], devVerts[state.f2], devVerts[state.f0]
+ };
+ hairProc(array, 4, clip, blitter.get());
+ }
+ }
+}