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 #include "gm/gm.h" 9 #include "include/core/SkBlendMode.h" 10 #include "include/core/SkCanvas.h" 11 #include "include/core/SkColor.h" 12 #include "include/core/SkMatrix.h" 13 #include "include/core/SkPaint.h" 14 #include "include/core/SkRRect.h" 15 #include "include/core/SkRect.h" 16 #include "include/core/SkScalar.h" 17 #include "include/core/SkSize.h" 18 #include "include/core/SkString.h" 19 #include "include/core/SkTypes.h" 20 #include "include/private/gpu/ganesh/GrTypesPriv.h" 21 #include "src/core/SkCanvasPriv.h" 22 #include "src/gpu/ganesh/GrCanvas.h" 23 #include "src/gpu/ganesh/GrCaps.h" 24 #include "src/gpu/ganesh/GrFragmentProcessor.h" 25 #include "src/gpu/ganesh/GrPaint.h" 26 #include "src/gpu/ganesh/SurfaceDrawContext.h" 27 #include "src/gpu/ganesh/effects/GrPorterDuffXferProcessor.h" 28 #include "src/gpu/ganesh/effects/GrRRectEffect.h" 29 #include "src/gpu/ganesh/ops/FillRectOp.h" 30 #include "src/gpu/ganesh/ops/GrDrawOp.h" 31 #include "tools/ToolUtils.h" 32 33 #include <memory> 34 #include <utility> 35 36 namespace skiagm { 37 38 /////////////////////////////////////////////////////////////////////////////// 39 40 class BigRRectAAEffectGM : public GpuGM { 41 public: BigRRectAAEffectGM(const SkRRect & rrect,const char * name)42 BigRRectAAEffectGM(const SkRRect& rrect, const char* name) 43 : fRRect(rrect) 44 , fName(name) { 45 this->setBGColor(ToolUtils::color_to_565(SK_ColorBLUE)); 46 // Each test case draws the rrect with gaps around it. 47 fTestWidth = SkScalarCeilToInt(rrect.width()) + 2 * kGap; 48 fTestHeight = SkScalarCeilToInt(rrect.height()) + 2 * kGap; 49 50 // Add a pad between test cases. 51 fTestOffsetX = fTestWidth + kPad; 52 fTestOffsetY = fTestHeight + kPad; 53 54 // We draw two tests in x (fill and inv-fill) and pad around 55 // all four sides of the image. 56 fWidth = 2 * fTestOffsetX + kPad; 57 fHeight = fTestOffsetY + kPad; 58 } 59 60 protected: getName() const61 SkString getName() const override { 62 SkString name; 63 name.printf("big_rrect_%s_aa_effect", fName); 64 return name; 65 } 66 getISize()67 SkISize getISize() override { return SkISize::Make(fWidth, fHeight); } 68 onDraw(GrRecordingContext * rContext,SkCanvas * canvas,SkString * errorMsg)69 DrawResult onDraw(GrRecordingContext* rContext, SkCanvas* canvas, SkString* errorMsg) override { 70 auto sdc = skgpu::ganesh::TopDeviceSurfaceDrawContext(canvas); 71 if (!sdc) { 72 *errorMsg = kErrorMsg_DrawSkippedGpuOnly; 73 return DrawResult::kSkip; 74 } 75 76 int y = kPad; 77 int x = kPad; 78 constexpr GrClipEdgeType kEdgeTypes[] = { 79 GrClipEdgeType::kFillAA, 80 GrClipEdgeType::kInverseFillAA, 81 }; 82 SkRect testBounds = SkRect::MakeIWH(fTestWidth, fTestHeight); 83 for (size_t et = 0; et < std::size(kEdgeTypes); ++et) { 84 GrClipEdgeType edgeType = kEdgeTypes[et]; 85 canvas->save(); 86 canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); 87 88 // Draw a background for the test case 89 SkPaint paint; 90 paint.setColor(SK_ColorWHITE); 91 canvas->drawRect(testBounds, paint); 92 93 SkRRect rrect = fRRect; 94 rrect.offset(SkIntToScalar(x + kGap), SkIntToScalar(y + kGap)); 95 const auto& caps = *rContext->priv().caps()->shaderCaps(); 96 auto [success, fp] = GrRRectEffect::Make(/*inputFP=*/nullptr, edgeType, rrect, 97 caps); 98 SkASSERT(success); 99 if (success) { 100 SkASSERT(fp); 101 GrPaint grPaint; 102 grPaint.setColor4f({ 0, 0, 0, 1.f }); 103 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); 104 grPaint.setCoverageFragmentProcessor(std::move(fp)); 105 106 SkRect bounds = testBounds; 107 bounds.offset(SkIntToScalar(x), SkIntToScalar(y)); 108 109 sdc->addDrawOp(skgpu::ganesh::FillRectOp::MakeNonAARect( 110 rContext, std::move(grPaint), SkMatrix::I(), bounds)); 111 } 112 canvas->restore(); 113 x = x + fTestOffsetX; 114 } 115 116 return DrawResult::kOk; 117 } 118 119 private: 120 // pad between test cases 121 inline static constexpr int kPad = 7; 122 // gap between rect for each case that is rendered and exterior of rrect 123 inline static constexpr int kGap = 3; 124 125 SkRRect fRRect; 126 int fWidth; 127 int fHeight; 128 int fTestWidth; 129 int fTestHeight; 130 int fTestOffsetX; 131 int fTestOffsetY; 132 const char* fName; 133 using INHERITED = GM; 134 }; 135 136 /////////////////////////////////////////////////////////////////////////////// 137 // This value is motivated by bug chromium:477684. It has to be large to cause overflow in 138 // the shader 139 constexpr int kSize = 700; 140 141 DEF_GM( return new BigRRectAAEffectGM (SkRRect::MakeRect(SkRect::MakeIWH(kSize, kSize)), "rect"); ) 142 DEF_GM( return new BigRRectAAEffectGM (SkRRect::MakeOval(SkRect::MakeIWH(kSize, kSize)), "circle"); ) 143 DEF_GM( return new BigRRectAAEffectGM (SkRRect::MakeOval(SkRect::MakeIWH(kSize - 1, kSize - 10)), "ellipse"); ) 144 // The next two have small linear segments between the corners 145 DEF_GM( return new BigRRectAAEffectGM (SkRRect::MakeRectXY(SkRect::MakeIWH(kSize - 1, kSize - 10), kSize/2.f - 10.f, kSize/2.f - 10.f), "circular_corner"); ) 146 DEF_GM( return new BigRRectAAEffectGM (SkRRect::MakeRectXY(SkRect::MakeIWH(kSize - 1, kSize - 10), kSize/2.f - 10.f, kSize/2.f - 15.f), "elliptical_corner"); ) 147 148 } // namespace skiagm 149