#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() {
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);
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) {
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) {
if (fUseObject) {
name.append("_object");
}
+ if (fShaderScale != 1) {
+ name.append("_scaled_shader");
+ }
return name;
}
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();
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;
}
#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) {
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;
}
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,
//
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);