skia2/gm/constcolorprocessor.cpp
Brian Osman 3695bdb587 Refactor SkMatrixProvider slightly
There was only one virtual method, so switch that to a bool stored in
the base class. The derived types exist as hints for the reader, and an
easy way to adjust how the new localToDevice is constructed.

With this change, we don't need SkSimpleMatrixProvider. SkMatrixProvider
is concrete, so we can use it directly. SkOverrideDeviceMatrixProvider
no longer needs the original provider for anything, so remove that
parameter. It now exists solely to inhibit the hitsPixelCenters flag.

Fix a few spots (SkParticleBinding, some sites in SkRuntimeEffect) where
we used SkSimpleMatrixProvider, even though the local coordinates being
passed did not obey the hits-pixel-centers constraints.

Most importantly, document how localToDeviceHitsPixelCenters works.

Change-Id: Ibe9060bac0822d0edf52a507d390bd198d8e6dbd
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/482176
Reviewed-by: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2021-12-09 20:10:58 +00:00

220 lines
8.4 KiB
C++

/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
// This test only works with the GPU backend.
#include "gm/gm.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontTypes.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.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/GrConfig.h"
#include "include/private/GrTypesPriv.h"
#include "include/private/SkColorData.h"
#include "src/core/SkCanvasPriv.h"
#include "src/core/SkMatrixProvider.h"
#include "src/gpu/GrColor.h"
#include "src/gpu/GrFragmentProcessor.h"
#include "src/gpu/GrPaint.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/ops/GrOp.h"
#include "src/gpu/v1/SurfaceDrawContext_v1.h"
#include "tools/ToolUtils.h"
#include "tools/gpu/TestOps.h"
#include <utility>
namespace skiagm {
/**
* This GM directly exercises Color and ModulateRGBA.
*/
class ColorProcessor : public GpuGM {
public:
enum class TestMode {
kConstColor,
kModulateRGBA
};
ColorProcessor(TestMode mode) : fMode(mode) {
this->setBGColor(0xFFDDDDDD);
}
protected:
SkString onShortName() override {
switch (fMode) {
case TestMode::kConstColor: return SkString("const_color_processor");
case TestMode::kModulateRGBA: return SkString("modulate_rgba");
}
SkUNREACHABLE;
}
SkISize onISize() override {
return SkISize::Make(kWidth, kHeight);
}
void onOnceBeforeDraw() override {
SkColor colors[] = { 0xFFFF0000, 0x2000FF00, 0xFF0000FF};
SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(kRectSize, kRectSize) };
fShader = SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors),
SkTileMode::kClamp);
}
DrawResult onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) override {
auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
if (!sdc) {
*errorMsg = kErrorMsg_DrawSkippedGpuOnly;
return DrawResult::kSkip;
}
constexpr GrColor kColors[] = {
0xFFFFFFFF,
0xFFFF00FF,
0x80000000,
0x00000000,
};
constexpr GrColor kPaintColors[] = {
0xFFFFFFFF,
0xFF0000FF,
0x80000080,
0x00000000,
};
SkScalar y = kPad;
SkScalar x = kPad;
SkScalar maxW = 0;
for (size_t paintType = 0; paintType < SK_ARRAY_COUNT(kPaintColors) + 1; ++paintType) {
for (size_t procColor = 0; procColor < SK_ARRAY_COUNT(kColors); ++procColor) {
// translate by x,y for the canvas draws and the test target draws.
canvas->save();
canvas->translate(x, y);
// rect to draw
SkRect renderRect = SkRect::MakeXYWH(0, 0, kRectSize, kRectSize);
// Create a base-layer FP for the const color processor to draw on top of.
std::unique_ptr<GrFragmentProcessor> baseFP;
if (paintType >= SK_ARRAY_COUNT(kPaintColors)) {
GrColorInfo colorInfo;
GrFPArgs args(rContext, SkMatrixProvider(SkMatrix::I()), &colorInfo);
baseFP = as_SB(fShader)->asFragmentProcessor(args);
} else {
baseFP = GrFragmentProcessor::MakeColor(
SkPMColor4f::FromBytes_RGBA(kPaintColors[paintType]));
}
// Layer a color/modulation FP on top of the base layer, using various colors.
std::unique_ptr<GrFragmentProcessor> colorFP;
switch (fMode) {
case TestMode::kConstColor:
colorFP = GrFragmentProcessor::MakeColor(
SkPMColor4f::FromBytes_RGBA(kColors[procColor]));
break;
case TestMode::kModulateRGBA:
colorFP = GrFragmentProcessor::ModulateRGBA(
std::move(baseFP), SkPMColor4f::FromBytes_RGBA(kColors[procColor]));
break;
}
// Render the FP tree.
if (auto op = sk_gpu_test::test_ops::MakeRect(rContext,
std::move(colorFP),
renderRect.makeOffset(x, y),
renderRect,
SkMatrix::I())) {
sdc->addDrawOp(std::move(op));
}
// Draw labels for the input to the processor and the processor to the right of
// the test rect. The input label appears above the processor label.
SkFont labelFont;
labelFont.setTypeface(ToolUtils::create_portable_typeface());
labelFont.setEdging(SkFont::Edging::kAntiAlias);
labelFont.setSize(10.f);
SkPaint labelPaint;
labelPaint.setAntiAlias(true);
SkString inputLabel("Input: ");
if (paintType >= SK_ARRAY_COUNT(kPaintColors)) {
inputLabel.append("gradient");
} else {
inputLabel.appendf("0x%08x", kPaintColors[paintType]);
}
SkString procLabel;
procLabel.printf("Proc: [0x%08x]", kColors[procColor]);
SkRect inputLabelBounds;
// get the bounds of the text in order to position it
labelFont.measureText(inputLabel.c_str(), inputLabel.size(),
SkTextEncoding::kUTF8, &inputLabelBounds);
canvas->drawString(inputLabel, renderRect.fRight + kPad, -inputLabelBounds.fTop,
labelFont, labelPaint);
// update the bounds to reflect the offset we used to draw it.
inputLabelBounds.offset(renderRect.fRight + kPad, -inputLabelBounds.fTop);
SkRect procLabelBounds;
labelFont.measureText(procLabel.c_str(), procLabel.size(),
SkTextEncoding::kUTF8, &procLabelBounds);
canvas->drawString(procLabel, renderRect.fRight + kPad,
inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop,
labelFont, labelPaint);
procLabelBounds.offset(renderRect.fRight + kPad,
inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop);
labelPaint.setStrokeWidth(0);
labelPaint.setStyle(SkPaint::kStroke_Style);
canvas->drawRect(renderRect, labelPaint);
canvas->restore();
// update x and y for the next test case.
SkScalar height = renderRect.height();
SkScalar width = std::max(inputLabelBounds.fRight, procLabelBounds.fRight);
maxW = std::max(maxW, width);
y += height + kPad;
if (y + height > kHeight) {
y = kPad;
x += maxW + kPad;
maxW = 0;
}
}
}
return DrawResult::kOk;
}
private:
// Use this as a way of generating an input FP
sk_sp<SkShader> fShader;
TestMode fMode;
inline static constexpr SkScalar kPad = 10.f;
inline static constexpr SkScalar kRectSize = 20.f;
inline static constexpr int kWidth = 820;
inline static constexpr int kHeight = 500;
using INHERITED = GM;
};
DEF_GM(return new ColorProcessor{ColorProcessor::TestMode::kConstColor};)
DEF_GM(return new ColorProcessor{ColorProcessor::TestMode::kModulateRGBA};)
} // namespace skiagm