4429a4f82c
It's been driving me nuts that I can't just write `SkMatrix44 m;`, and I often don't care whether it's initialized or not. The default identity constructor would be nice to use, but it's deprecated. By tagging this constructor deprecated, we're only hurting ourselves; our big clients disable warnings about deprecated routines and use it freely. A quick tally in Skia shows we mostly use the uninitialized constructor, but sometimes the identity constructor, and there is a spread of all three in Chromium. So I've left the two explicit calls available. I switched a bunch of calls in Skia to use the less verbose constructor where it was clear that it didn't matter if the matrix was initialized. Literally zero of the kUninitialized constructor calls looked important for performance, so the only place I've kept is its lone unit test. A few places read clearer with an explicit "identity" to read. Change-Id: I0573cb6201f5a36f3b43070fb111f7d9af92736f Reviewed-on: https://skia-review.googlesource.com/c/159480 Reviewed-by: Brian Osman <brianosman@google.com>
238 lines
9.0 KiB
C++
238 lines
9.0 KiB
C++
/*
|
|
* Copyright 2016 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 "sk_tool_utils.h"
|
|
|
|
#include "SkGradientShader.h"
|
|
#include "SkImagePriv.h"
|
|
#include "SkSurface.h"
|
|
#include "SkVertices.h"
|
|
|
|
static const int gRectSize = 50;
|
|
static const SkScalar gScalarSize = SkIntToScalar(gRectSize);
|
|
static const int gTestWidth = 700;
|
|
static const int gTestHeight = 300;
|
|
|
|
struct CellRenderer {
|
|
virtual void draw(SkCanvas* canvas) = 0;
|
|
virtual const char* label() = 0;
|
|
virtual ~CellRenderer() {}
|
|
};
|
|
|
|
struct PaintColorCellRenderer : public CellRenderer {
|
|
PaintColorCellRenderer(SkColor color) : fColor(color) {}
|
|
void draw(SkCanvas* canvas) override {
|
|
canvas->drawColor(fColor);
|
|
}
|
|
const char* label() override {
|
|
return "Paint Color";
|
|
}
|
|
protected:
|
|
SkColor fColor;
|
|
};
|
|
|
|
struct BitmapCellRenderer : public CellRenderer {
|
|
BitmapCellRenderer(SkColor color, SkFilterQuality quality, float scale = 1.0f)
|
|
: fQuality(quality) {
|
|
int scaledSize = sk_float_round2int(scale * gRectSize);
|
|
fBitmap.allocPixels(SkImageInfo::MakeS32(scaledSize, scaledSize, kPremul_SkAlphaType));
|
|
fBitmap.eraseColor(color);
|
|
fBitmap.setImmutable();
|
|
const char* qualityNames[] = { "None", "Low", "Medium", "High" };
|
|
fLabel = SkStringPrintf("Bitmap (%s)", qualityNames[quality]);
|
|
}
|
|
void draw(SkCanvas* canvas) override {
|
|
SkPaint paint;
|
|
paint.setFilterQuality(fQuality);
|
|
canvas->drawBitmapRect(fBitmap, SkRect::MakeIWH(gRectSize, gRectSize), &paint);
|
|
}
|
|
const char* label() override {
|
|
return fLabel.c_str();
|
|
}
|
|
protected:
|
|
SkFilterQuality fQuality;
|
|
SkBitmap fBitmap;
|
|
SkString fLabel;
|
|
};
|
|
|
|
struct GradientCellRenderer : public CellRenderer {
|
|
GradientCellRenderer(SkColor colorOne, SkColor colorTwo, bool manyStops) {
|
|
fColors[0] = colorOne;
|
|
fColors[1] = colorTwo;
|
|
fManyStops = manyStops;
|
|
}
|
|
void draw(SkCanvas* canvas) override {
|
|
SkPoint points[2] = {
|
|
SkPoint::Make(0, 0),
|
|
SkPoint::Make(0, gScalarSize)
|
|
};
|
|
SkPaint paint;
|
|
if (fManyStops) {
|
|
SkColor colors[4] ={
|
|
fColors[0], fColors[0], fColors[1], fColors[1]
|
|
};
|
|
paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
|
|
SkShader::kClamp_TileMode));
|
|
} else {
|
|
paint.setShader(SkGradientShader::MakeLinear(points, fColors, nullptr, 2,
|
|
SkShader::kClamp_TileMode));
|
|
}
|
|
canvas->drawPaint(paint);
|
|
}
|
|
const char* label() override {
|
|
return "Linear Gradient";
|
|
}
|
|
protected:
|
|
SkColor fColors[2];
|
|
bool fManyStops;
|
|
};
|
|
|
|
struct VerticesCellRenderer : public CellRenderer {
|
|
VerticesCellRenderer(SkColor colorOne, SkColor colorTwo) {
|
|
fColors[0] = fColors[1] = colorOne;
|
|
fColors[2] = fColors[3] = colorTwo;
|
|
}
|
|
void draw(SkCanvas* canvas) override {
|
|
SkPaint paint;
|
|
SkPoint vertices[4] = {
|
|
SkPoint::Make(0, 0),
|
|
SkPoint::Make(gScalarSize, 0),
|
|
SkPoint::Make(gScalarSize, gScalarSize),
|
|
SkPoint::Make(0, gScalarSize)
|
|
};
|
|
canvas->drawVertices(SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4, vertices,
|
|
nullptr, fColors),
|
|
SkBlendMode::kModulate, paint);
|
|
}
|
|
const char* label() override {
|
|
return "Vertices";
|
|
}
|
|
protected:
|
|
SkColor fColors[4];
|
|
};
|
|
|
|
static void draw_gamut_grid(SkCanvas* canvas, SkTArray<std::unique_ptr<CellRenderer>>& renderers) {
|
|
// We want our colors in our wide gamut to be obviously visibly distorted from sRGB, so we use
|
|
// Wide Gamut RGB (with sRGB gamma, for HW acceleration) as the working space for this test:
|
|
const float gWideGamutRGB_toXYZD50[]{
|
|
0.7161046f, 0.1009296f, 0.1471858f, // -> X
|
|
0.2581874f, 0.7249378f, 0.0168748f, // -> Y
|
|
0.0000000f, 0.0517813f, 0.7734287f, // -> Z
|
|
};
|
|
|
|
SkMatrix44 wideGamutRGB_toXYZD50;
|
|
wideGamutRGB_toXYZD50.set3x3RowMajorf(gWideGamutRGB_toXYZD50);
|
|
|
|
// Use the original canvas' color type, but account for gamma requirements
|
|
SkImageInfo origInfo = canvas->imageInfo();
|
|
sk_sp<SkColorSpace> srgbCS;
|
|
sk_sp<SkColorSpace> wideCS;
|
|
switch (origInfo.colorType()) {
|
|
case kRGBA_8888_SkColorType:
|
|
case kBGRA_8888_SkColorType:
|
|
srgbCS = SkColorSpace::MakeSRGB();
|
|
wideCS = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
|
|
wideGamutRGB_toXYZD50);
|
|
break;
|
|
case kRGBA_F16_SkColorType:
|
|
case kRGBA_F32_SkColorType:
|
|
srgbCS = SkColorSpace::MakeSRGBLinear();
|
|
wideCS = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
|
|
wideGamutRGB_toXYZD50);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
SkASSERT(srgbCS);
|
|
SkASSERT(wideCS);
|
|
|
|
// Make our two working surfaces (one sRGB, one Wide)
|
|
SkImageInfo srgbGamutInfo = SkImageInfo::Make(gRectSize, gRectSize, origInfo.colorType(),
|
|
kPremul_SkAlphaType, srgbCS);
|
|
SkImageInfo wideGamutInfo = SkImageInfo::Make(gRectSize, gRectSize, origInfo.colorType(),
|
|
kPremul_SkAlphaType, wideCS);
|
|
|
|
sk_sp<SkSurface> srgbGamutSurface = canvas->makeSurface(srgbGamutInfo);
|
|
sk_sp<SkSurface> wideGamutSurface = canvas->makeSurface(wideGamutInfo);
|
|
if (!srgbGamutSurface || !wideGamutSurface) {
|
|
return;
|
|
}
|
|
SkCanvas* srgbGamutCanvas = srgbGamutSurface->getCanvas();
|
|
SkCanvas* wideGamutCanvas = wideGamutSurface->getCanvas();
|
|
|
|
SkPaint textPaint;
|
|
textPaint.setAntiAlias(true);
|
|
textPaint.setColor(SK_ColorWHITE);
|
|
sk_tool_utils::set_portable_typeface(&textPaint);
|
|
|
|
SkScalar x = 0, y = 0;
|
|
SkScalar textHeight = textPaint.getFontSpacing();
|
|
|
|
for (const auto& renderer : renderers) {
|
|
srgbGamutCanvas->clear(SK_ColorBLACK);
|
|
renderer->draw(srgbGamutCanvas);
|
|
wideGamutCanvas->clear(SK_ColorBLACK);
|
|
renderer->draw(wideGamutCanvas);
|
|
|
|
canvas->drawString(renderer->label(), x, y + textHeight, textPaint);
|
|
|
|
// Re-interpret the off-screen images, so we can see the raw data (eg, Wide gamut squares
|
|
// will look desaturated, relative to sRGB).
|
|
auto srgbImage = srgbGamutSurface->makeImageSnapshot();
|
|
srgbImage = SkImageMakeRasterCopyAndAssignColorSpace(srgbImage.get(),
|
|
origInfo.colorSpace());
|
|
canvas->drawImage(srgbImage, x, y + textHeight + 5);
|
|
x += (gScalarSize + 1);
|
|
|
|
auto wideImage = wideGamutSurface->makeImageSnapshot();
|
|
wideImage = SkImageMakeRasterCopyAndAssignColorSpace(wideImage.get(),
|
|
origInfo.colorSpace());
|
|
canvas->drawImage(wideImage, x, y + textHeight + 5);
|
|
x += (gScalarSize + 10);
|
|
|
|
if (x + (2 * gScalarSize + 1) > gTestWidth) {
|
|
x = 0;
|
|
y += (textHeight + gScalarSize + 10);
|
|
}
|
|
}
|
|
}
|
|
|
|
DEF_SIMPLE_GM_BG(gamut, canvas, gTestWidth, gTestHeight, SK_ColorBLACK) {
|
|
SkTArray<std::unique_ptr<CellRenderer>> renderers;
|
|
|
|
// sRGB primaries, rendered as paint color
|
|
renderers.emplace_back(new PaintColorCellRenderer(SK_ColorRED));
|
|
renderers.emplace_back(new PaintColorCellRenderer(SK_ColorGREEN));
|
|
|
|
// sRGB primaries, rendered as bitmaps
|
|
renderers.emplace_back(new BitmapCellRenderer(SK_ColorRED, kNone_SkFilterQuality));
|
|
renderers.emplace_back(new BitmapCellRenderer(SK_ColorGREEN, kLow_SkFilterQuality));
|
|
// Larger bitmap to trigger mipmaps
|
|
renderers.emplace_back(new BitmapCellRenderer(SK_ColorRED, kMedium_SkFilterQuality, 2.0f));
|
|
// Smaller bitmap to trigger bicubic
|
|
renderers.emplace_back(new BitmapCellRenderer(SK_ColorGREEN, kHigh_SkFilterQuality, 0.5f));
|
|
|
|
// Various gradients involving sRGB primaries and white/black
|
|
|
|
// First with just two stops (implemented with uniforms on GPU)
|
|
renderers.emplace_back(new GradientCellRenderer(SK_ColorRED, SK_ColorGREEN, false));
|
|
renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorBLACK, false));
|
|
renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorWHITE, false));
|
|
|
|
// ... and then with four stops (implemented with textures on GPU)
|
|
renderers.emplace_back(new GradientCellRenderer(SK_ColorRED, SK_ColorGREEN, true));
|
|
renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorBLACK, true));
|
|
renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorWHITE, true));
|
|
|
|
// Vertex colors
|
|
renderers.emplace_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorRED));
|
|
renderers.emplace_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorGREEN));
|
|
|
|
draw_gamut_grid(canvas, renderers);
|
|
}
|