skia2/gm/drawquadset.cpp
Brian Osman 449b1157a7 Plumb SkMatrixProvider throughout Ganesh
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>
2020-04-20 13:48:40 +00:00

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