blob: d5602ebb8773f818b4540b1d13d35a3e8ef71424 [file] [log] [blame]
/*
* 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, ModulateRGBA and ModulateAlpha.
*/
class ColorProcessor : public GpuGM {
public:
enum class TestMode {
kConstColor,
kModulateRGBA,
kModulateAlpha
};
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");
case TestMode::kModulateAlpha: return SkString("modulate_alpha");
}
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, SkSimpleMatrixProvider(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;
case TestMode::kModulateAlpha:
colorFP = GrFragmentProcessor::ModulateAlpha(
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};)
DEF_GM(return new ColorProcessor{ColorProcessor::TestMode::kModulateAlpha};)
} // namespace skiagm