449b1157a7
Renames the provider to SkMatrixProvider, which is now also able to provide the local-to-device matrix. Everywhere that does paint conversion and FP generation now has access to the entire matrix provider, instead of just the CTM. This will allow the SkSL FP (and others) to fetch other matrix state. Change-Id: Iffb00bae0d438da0e8de3eebe75183ed6d440fd6 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/284040 Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Michael Ludwig <michaelludwig@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
247 lines
9.2 KiB
C++
247 lines
9.2 KiB
C++
/*
|
|
* Copyright 2018 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "gm/gm.h"
|
|
#include "include/core/SkBlendMode.h"
|
|
#include "include/core/SkCanvas.h"
|
|
#include "include/core/SkColor.h"
|
|
#include "include/core/SkFont.h"
|
|
#include "include/core/SkMatrix.h"
|
|
#include "include/core/SkPaint.h"
|
|
#include "include/core/SkPoint.h"
|
|
#include "include/core/SkRect.h"
|
|
#include "include/core/SkScalar.h"
|
|
#include "include/core/SkShader.h"
|
|
#include "include/core/SkSize.h"
|
|
#include "include/core/SkString.h"
|
|
#include "include/core/SkTileMode.h"
|
|
#include "include/core/SkTypeface.h"
|
|
#include "include/core/SkTypes.h"
|
|
#include "include/effects/SkGradientShader.h"
|
|
#include "include/gpu/GrContext.h"
|
|
#include "include/private/GrTypesPriv.h"
|
|
#include "src/core/SkMatrixProvider.h"
|
|
#include "src/gpu/GrClip.h"
|
|
#include "src/gpu/GrPaint.h"
|
|
#include "src/gpu/GrRenderTargetContext.h"
|
|
#include "src/gpu/SkGr.h"
|
|
|
|
#include <utility>
|
|
|
|
static constexpr SkScalar kTileWidth = 40;
|
|
static constexpr SkScalar kTileHeight = 30;
|
|
|
|
static constexpr int kRowCount = 4;
|
|
static constexpr int kColCount = 3;
|
|
|
|
static void draw_text(SkCanvas* canvas, const char* text) {
|
|
canvas->drawString(text, 0, 0, SkFont(nullptr, 12), SkPaint());
|
|
}
|
|
|
|
static void draw_gradient_tiles(SkCanvas* canvas, bool alignGradients) {
|
|
// Always draw the same gradient
|
|
static constexpr SkPoint pts[] = { {0.f, 0.f}, {0.25f * kTileWidth, 0.25f * kTileHeight} };
|
|
static constexpr SkColor colors[] = { SK_ColorBLUE, SK_ColorWHITE };
|
|
|
|
GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
|
|
|
|
GrContext* context = canvas->getGrContext();
|
|
|
|
auto gradient = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kMirror);
|
|
SkPaint paint;
|
|
paint.setShader(gradient);
|
|
|
|
for (int i = 0; i < kRowCount; ++i) {
|
|
for (int j = 0; j < kColCount; ++j) {
|
|
SkRect tile = SkRect::MakeWH(kTileWidth, kTileHeight);
|
|
if (alignGradients) {
|
|
tile.offset(j * kTileWidth, i * kTileHeight);
|
|
} else {
|
|
canvas->save();
|
|
canvas->translate(j * kTileWidth, i * kTileHeight);
|
|
}
|
|
|
|
unsigned aa = SkCanvas::kNone_QuadAAFlags;
|
|
if (i == 0) {
|
|
aa |= SkCanvas::kTop_QuadAAFlag;
|
|
}
|
|
if (i == kRowCount - 1) {
|
|
aa |= SkCanvas::kBottom_QuadAAFlag;
|
|
}
|
|
if (j == 0) {
|
|
aa |= SkCanvas::kLeft_QuadAAFlag;
|
|
}
|
|
if (j == kColCount - 1) {
|
|
aa |= SkCanvas::kRight_QuadAAFlag;
|
|
}
|
|
|
|
if (rtc) {
|
|
// Use non-public API to leverage general GrPaint capabilities
|
|
SkMatrix view = canvas->getTotalMatrix();
|
|
SkSimpleMatrixProvider matrixProvider(view);
|
|
GrPaint grPaint;
|
|
SkPaintToGrPaint(context, rtc->colorInfo(), paint, matrixProvider, &grPaint);
|
|
rtc->fillRectWithEdgeAA(GrNoClip(), std::move(grPaint), GrAA::kYes,
|
|
static_cast<GrQuadAAFlags>(aa), view, tile);
|
|
} else {
|
|
// Fallback to solid color on raster backend since the public API only has color
|
|
SkColor color = alignGradients ? SK_ColorBLUE
|
|
: (i * kColCount + j) % 2 == 0 ? SK_ColorBLUE
|
|
: SK_ColorWHITE;
|
|
canvas->experimental_DrawEdgeAAQuad(
|
|
tile, nullptr, static_cast<SkCanvas::QuadAAFlags>(aa), color,
|
|
SkBlendMode::kSrcOver);
|
|
}
|
|
|
|
if (!alignGradients) {
|
|
// Pop off the matrix translation when drawing unaligned
|
|
canvas->restore();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void draw_color_tiles(SkCanvas* canvas, bool multicolor) {
|
|
for (int i = 0; i < kRowCount; ++i) {
|
|
for (int j = 0; j < kColCount; ++j) {
|
|
SkRect tile = SkRect::MakeXYWH(j * kTileWidth, i * kTileHeight, kTileWidth, kTileHeight);
|
|
|
|
SkColor4f color;
|
|
if (multicolor) {
|
|
color = {(i + 1.f) / kRowCount, (j + 1.f) / kColCount, .4f, 1.f};
|
|
} else {
|
|
color = {.2f, .8f, .3f, 1.f};
|
|
}
|
|
|
|
unsigned aa = SkCanvas::kNone_QuadAAFlags;
|
|
if (i == 0) {
|
|
aa |= SkCanvas::kTop_QuadAAFlag;
|
|
}
|
|
if (i == kRowCount - 1) {
|
|
aa |= SkCanvas::kBottom_QuadAAFlag;
|
|
}
|
|
if (j == 0) {
|
|
aa |= SkCanvas::kLeft_QuadAAFlag;
|
|
}
|
|
if (j == kColCount - 1) {
|
|
aa |= SkCanvas::kRight_QuadAAFlag;
|
|
}
|
|
|
|
canvas->experimental_DrawEdgeAAQuad(
|
|
tile, nullptr, static_cast<SkCanvas::QuadAAFlags>(aa), color.toSkColor(),
|
|
SkBlendMode::kSrcOver);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void draw_tile_boundaries(SkCanvas* canvas, const SkMatrix& local) {
|
|
// Draw grid of red lines at interior tile boundaries.
|
|
static constexpr SkScalar kLineOutset = 10.f;
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setColor(SK_ColorRED);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(0.f);
|
|
for (int x = 1; x < kColCount; ++x) {
|
|
SkPoint pts[] = {{x * kTileWidth, 0}, {x * kTileWidth, kRowCount * kTileHeight}};
|
|
local.mapPoints(pts, 2);
|
|
SkVector v = pts[1] - pts[0];
|
|
v.setLength(v.length() + kLineOutset);
|
|
canvas->drawLine(pts[1] - v, pts[0] + v, paint);
|
|
}
|
|
for (int y = 1; y < kRowCount; ++y) {
|
|
SkPoint pts[] = {{0, y * kTileHeight}, {kTileWidth * kColCount, y * kTileHeight}};
|
|
local.mapPoints(pts, 2);
|
|
SkVector v = pts[1] - pts[0];
|
|
v.setLength(v.length() + kLineOutset);
|
|
canvas->drawLine(pts[1] - v, pts[0] + v, paint);
|
|
}
|
|
}
|
|
|
|
// Tile renderers (column variation)
|
|
typedef void (*TileRenderer)(SkCanvas*);
|
|
static TileRenderer kTileSets[] = {
|
|
[](SkCanvas* canvas) { draw_gradient_tiles(canvas, /* aligned */ false); },
|
|
[](SkCanvas* canvas) { draw_gradient_tiles(canvas, /* aligned */ true); },
|
|
[](SkCanvas* canvas) { draw_color_tiles(canvas, /* multicolor */ false); },
|
|
[](SkCanvas* canvas) { draw_color_tiles(canvas, /* multicolor */true); },
|
|
};
|
|
static const char* kTileSetNames[] = { "Local", "Aligned", "Green", "Multicolor" };
|
|
static_assert(SK_ARRAY_COUNT(kTileSets) == SK_ARRAY_COUNT(kTileSetNames), "Count mismatch");
|
|
|
|
namespace skiagm {
|
|
|
|
class DrawQuadSetGM : public GM {
|
|
private:
|
|
SkString onShortName() override { return SkString("draw_quad_set"); }
|
|
SkISize onISize() override { return SkISize::Make(800, 800); }
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
SkMatrix rowMatrices[5];
|
|
// Identity
|
|
rowMatrices[0].setIdentity();
|
|
// Translate/scale
|
|
rowMatrices[1].setTranslate(5.5f, 20.25f);
|
|
rowMatrices[1].postScale(.9f, .7f);
|
|
// Rotation
|
|
rowMatrices[2].setRotate(20.0f);
|
|
rowMatrices[2].preTranslate(15.f, -20.f);
|
|
// Skew
|
|
rowMatrices[3].setSkew(.5f, .25f);
|
|
rowMatrices[3].preTranslate(-30.f, 0.f);
|
|
// Perspective
|
|
SkPoint src[4];
|
|
SkRect::MakeWH(kColCount * kTileWidth, kRowCount * kTileHeight).toQuad(src);
|
|
SkPoint dst[4] = {{0, 0},
|
|
{kColCount * kTileWidth + 10.f, 15.f},
|
|
{kColCount * kTileWidth - 28.f, kRowCount * kTileHeight + 40.f},
|
|
{25.f, kRowCount * kTileHeight - 15.f}};
|
|
SkAssertResult(rowMatrices[4].setPolyToPoly(src, dst, 4));
|
|
rowMatrices[4].preTranslate(0.f, +10.f);
|
|
static const char* matrixNames[] = { "Identity", "T+S", "Rotate", "Skew", "Perspective" };
|
|
static_assert(SK_ARRAY_COUNT(matrixNames) == SK_ARRAY_COUNT(rowMatrices), "Count mismatch");
|
|
|
|
// Print a column header
|
|
canvas->save();
|
|
canvas->translate(110.f, 20.f);
|
|
for (size_t j = 0; j < SK_ARRAY_COUNT(kTileSetNames); ++j) {
|
|
draw_text(canvas, kTileSetNames[j]);
|
|
canvas->translate(kColCount * kTileWidth + 30.f, 0.f);
|
|
}
|
|
canvas->restore();
|
|
canvas->translate(0.f, 40.f);
|
|
|
|
// Render all tile variations
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(rowMatrices); ++i) {
|
|
canvas->save();
|
|
canvas->translate(10.f, 0.5f * kRowCount * kTileHeight);
|
|
draw_text(canvas, matrixNames[i]);
|
|
|
|
canvas->translate(100.f, -0.5f * kRowCount * kTileHeight);
|
|
for (size_t j = 0; j < SK_ARRAY_COUNT(kTileSets); ++j) {
|
|
canvas->save();
|
|
draw_tile_boundaries(canvas, rowMatrices[i]);
|
|
|
|
canvas->concat(rowMatrices[i]);
|
|
kTileSets[j](canvas);
|
|
// Undo the local transformation
|
|
canvas->restore();
|
|
// And advance to the next column
|
|
canvas->translate(kColCount * kTileWidth + 30.f, 0.f);
|
|
}
|
|
// Reset back to the left edge
|
|
canvas->restore();
|
|
// And advance to the next row
|
|
canvas->translate(0.f, kRowCount * kTileHeight + 20.f);
|
|
}
|
|
}
|
|
};
|
|
|
|
DEF_GM(return new DrawQuadSetGM();)
|
|
|
|
} // namespace skiagm
|