136f45a636
With this formalization, the edge-AA APIs in GrRTC can distinguish between tiling cases and regular drawing cases implemented using kNone or kAll for the AA flags. This means fillRectToRect can be implemented in terms of fillRectWithEdgeAA. It also means the drawTexture cases will properly handle isolated draws and tiled draws when drawing into MSAA. Bug: skia: Change-Id: I248dd001919228a958cf84b6bc91363b58b72c0b Reviewed-on: https://skia-review.googlesource.com/c/192023 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
227 lines
8.5 KiB
C++
227 lines
8.5 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.h"
|
|
|
|
#include "GrClip.h"
|
|
#include "GrContext.h"
|
|
#include "GrRenderTargetContext.h"
|
|
#include "GrSurfaceContextPriv.h"
|
|
#include "SkGr.h"
|
|
#include "SkGradientShader.h"
|
|
|
|
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, SkShader::kMirror_TileMode);
|
|
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();
|
|
GrPaint grPaint;
|
|
SkPaintToGrPaint(context, rtc->colorSpaceInfo(), paint, view, &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_DrawEdgeAARectV1(
|
|
tile, 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_DrawEdgeAARectV1(
|
|
tile, 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() final { 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
|