1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 // This test only works with the GPU backend. 9 10 #include "gm/gm.h" 11 #include "include/core/SkCanvas.h" 12 #include "include/core/SkColor.h" 13 #include "include/core/SkFont.h" 14 #include "include/core/SkFontTypes.h" 15 #include "include/core/SkMatrix.h" 16 #include "include/core/SkPaint.h" 17 #include "include/core/SkPoint.h" 18 #include "include/core/SkRect.h" 19 #include "include/core/SkRefCnt.h" 20 #include "include/core/SkScalar.h" 21 #include "include/core/SkShader.h" 22 #include "include/core/SkSize.h" 23 #include "include/core/SkString.h" 24 #include "include/core/SkTileMode.h" 25 #include "include/core/SkTypeface.h" 26 #include "include/core/SkTypes.h" 27 #include "include/effects/SkGradientShader.h" 28 #include "include/gpu/GrConfig.h" 29 #include "include/private/GrTypesPriv.h" 30 #include "include/private/SkColorData.h" 31 #include "src/core/SkCanvasPriv.h" 32 #include "src/core/SkMatrixProvider.h" 33 #include "src/gpu/GrColor.h" 34 #include "src/gpu/GrFragmentProcessor.h" 35 #include "src/gpu/GrPaint.h" 36 #include "src/gpu/SkGr.h" 37 #include "src/gpu/ops/GrOp.h" 38 #include "src/gpu/v1/SurfaceDrawContext_v1.h" 39 #include "tools/ToolUtils.h" 40 #include "tools/gpu/TestOps.h" 41 42 #include <utility> 43 44 namespace skiagm { 45 /** 46 * This GM directly exercises Color and ModulateRGBA. 47 */ 48 class ColorProcessor : public GpuGM { 49 public: 50 enum class TestMode { 51 kConstColor, 52 kModulateRGBA 53 }; 54 ColorProcessor(TestMode mode)55 ColorProcessor(TestMode mode) : fMode(mode) { 56 this->setBGColor(0xFFDDDDDD); 57 } 58 59 protected: onShortName()60 SkString onShortName() override { 61 switch (fMode) { 62 case TestMode::kConstColor: return SkString("const_color_processor"); 63 case TestMode::kModulateRGBA: return SkString("modulate_rgba"); 64 } 65 SkUNREACHABLE; 66 } 67 onISize()68 SkISize onISize() override { 69 return SkISize::Make(kWidth, kHeight); 70 } 71 onOnceBeforeDraw()72 void onOnceBeforeDraw() override { 73 SkColor colors[] = { 0xFFFF0000, 0x2000FF00, 0xFF0000FF}; 74 SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(kRectSize, kRectSize) }; 75 fShader = SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors), 76 SkTileMode::kClamp); 77 } 78 onDraw(GrRecordingContext * rContext,SkCanvas * canvas,SkString * errorMsg)79 DrawResult onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) override { 80 auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas); 81 if (!sdc) { 82 *errorMsg = kErrorMsg_DrawSkippedGpuOnly; 83 return DrawResult::kSkip; 84 } 85 86 constexpr GrColor kColors[] = { 87 0xFFFFFFFF, 88 0xFFFF00FF, 89 0x80000000, 90 0x00000000, 91 }; 92 93 constexpr GrColor kPaintColors[] = { 94 0xFFFFFFFF, 95 0xFF0000FF, 96 0x80000080, 97 0x00000000, 98 }; 99 100 SkScalar y = kPad; 101 SkScalar x = kPad; 102 SkScalar maxW = 0; 103 for (size_t paintType = 0; paintType < SK_ARRAY_COUNT(kPaintColors) + 1; ++paintType) { 104 for (size_t procColor = 0; procColor < SK_ARRAY_COUNT(kColors); ++procColor) { 105 // translate by x,y for the canvas draws and the test target draws. 106 canvas->save(); 107 canvas->translate(x, y); 108 109 // rect to draw 110 SkRect renderRect = SkRect::MakeXYWH(0, 0, kRectSize, kRectSize); 111 112 // Create a base-layer FP for the const color processor to draw on top of. 113 std::unique_ptr<GrFragmentProcessor> baseFP; 114 if (paintType >= SK_ARRAY_COUNT(kPaintColors)) { 115 GrColorInfo colorInfo; 116 GrFPArgs args(rContext, SkSimpleMatrixProvider(SkMatrix::I()), &colorInfo); 117 baseFP = as_SB(fShader)->asFragmentProcessor(args); 118 } else { 119 baseFP = GrFragmentProcessor::MakeColor( 120 SkPMColor4f::FromBytes_RGBA(kPaintColors[paintType])); 121 } 122 123 // Layer a color/modulation FP on top of the base layer, using various colors. 124 std::unique_ptr<GrFragmentProcessor> colorFP; 125 switch (fMode) { 126 case TestMode::kConstColor: 127 colorFP = GrFragmentProcessor::MakeColor( 128 SkPMColor4f::FromBytes_RGBA(kColors[procColor])); 129 break; 130 131 case TestMode::kModulateRGBA: 132 colorFP = GrFragmentProcessor::ModulateRGBA( 133 std::move(baseFP), SkPMColor4f::FromBytes_RGBA(kColors[procColor])); 134 break; 135 } 136 137 // Render the FP tree. 138 if (auto op = sk_gpu_test::test_ops::MakeRect(rContext, 139 std::move(colorFP), 140 renderRect.makeOffset(x, y), 141 renderRect, 142 SkMatrix::I())) { 143 sdc->addDrawOp(std::move(op)); 144 } 145 146 // Draw labels for the input to the processor and the processor to the right of 147 // the test rect. The input label appears above the processor label. 148 SkFont labelFont; 149 labelFont.setTypeface(ToolUtils::create_portable_typeface()); 150 labelFont.setEdging(SkFont::Edging::kAntiAlias); 151 labelFont.setSize(10.f); 152 SkPaint labelPaint; 153 labelPaint.setAntiAlias(true); 154 SkString inputLabel("Input: "); 155 if (paintType >= SK_ARRAY_COUNT(kPaintColors)) { 156 inputLabel.append("gradient"); 157 } else { 158 inputLabel.appendf("0x%08x", kPaintColors[paintType]); 159 } 160 SkString procLabel; 161 procLabel.printf("Proc: [0x%08x]", kColors[procColor]); 162 163 SkRect inputLabelBounds; 164 // get the bounds of the text in order to position it 165 labelFont.measureText(inputLabel.c_str(), inputLabel.size(), 166 SkTextEncoding::kUTF8, &inputLabelBounds); 167 canvas->drawString(inputLabel, renderRect.fRight + kPad, -inputLabelBounds.fTop, 168 labelFont, labelPaint); 169 // update the bounds to reflect the offset we used to draw it. 170 inputLabelBounds.offset(renderRect.fRight + kPad, -inputLabelBounds.fTop); 171 172 SkRect procLabelBounds; 173 labelFont.measureText(procLabel.c_str(), procLabel.size(), 174 SkTextEncoding::kUTF8, &procLabelBounds); 175 canvas->drawString(procLabel, renderRect.fRight + kPad, 176 inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop, 177 labelFont, labelPaint); 178 procLabelBounds.offset(renderRect.fRight + kPad, 179 inputLabelBounds.fBottom + 2.f - procLabelBounds.fTop); 180 181 labelPaint.setStrokeWidth(0); 182 labelPaint.setStyle(SkPaint::kStroke_Style); 183 canvas->drawRect(renderRect, labelPaint); 184 185 canvas->restore(); 186 187 // update x and y for the next test case. 188 SkScalar height = renderRect.height(); 189 SkScalar width = std::max(inputLabelBounds.fRight, procLabelBounds.fRight); 190 maxW = std::max(maxW, width); 191 y += height + kPad; 192 if (y + height > kHeight) { 193 y = kPad; 194 x += maxW + kPad; 195 maxW = 0; 196 } 197 } 198 } 199 200 return DrawResult::kOk; 201 } 202 203 private: 204 // Use this as a way of generating an input FP 205 sk_sp<SkShader> fShader; 206 TestMode fMode; 207 208 inline static constexpr SkScalar kPad = 10.f; 209 inline static constexpr SkScalar kRectSize = 20.f; 210 inline static constexpr int kWidth = 820; 211 inline static constexpr int kHeight = 500; 212 213 using INHERITED = GM; 214 }; 215 216 DEF_GM(return new ColorProcessor{ColorProcessor::TestMode::kConstColor};) 217 DEF_GM(return new ColorProcessor{ColorProcessor::TestMode::kModulateRGBA};) 218 219 } // namespace skiagm 220