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.h" 9 #if SK_SUPPORT_GPU 10 #include "GrContext.h" 11 #include "GrDrawContext.h" 12 #include "GrPipelineBuilder.h" 13 #include "SkDevice.h" 14 #include "SkRRect.h" 15 #include "batches/GrDrawBatch.h" 16 #include "batches/GrRectBatchFactory.h" 17 #include "effects/GrRRectEffect.h" 18 19 namespace skiagm { 20 21 /////////////////////////////////////////////////////////////////////////////// 22 23 class BigRRectAAEffectGM : public GM { 24 public: 25 BigRRectAAEffectGM(const SkRRect& rrect, const char* name) 26 : fRRect(rrect) 27 , fName(name) { 28 this->setBGColor(sk_tool_utils::color_to_565(SK_ColorBLUE)); 29 // Each test case draws the rrect with gaps around it. 30 fTestWidth = SkScalarCeilToInt(rrect.width()) + 2 * kGap; 31 fTestHeight = SkScalarCeilToInt(rrect.height()) + 2 * kGap; 32 33 // Add a pad between test cases. 34 fTestOffsetX = fTestWidth + kPad; 35 fTestOffsetY = fTestHeight + kPad; 36 37 // We draw two tests in x (fill and inv-fill) and pad around 38 // all four sides of the image. 39 fWidth = 2 * fTestOffsetX + kPad; 40 fHeight = fTestOffsetY + kPad; 41 } 42 43 protected: 44 SkString onShortName() override { 45 SkString name; 46 name.printf("big_rrect_%s_aa_effect", fName); 47 return name; 48 } 49 50 SkISize onISize() override { return SkISize::Make(fWidth, fHeight); } 51 52 void onDraw(SkCanvas* canvas) override { 53 GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget(); 54 GrContext* context = rt ? rt->getContext() : nullptr; 55 if (!context) { 56 skiagm::GM::DrawGpuOnlyMessage(canvas); 57 return; 58 } 59 60 SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(rt)); 61 if (!drawContext) { 62 return; 63 } 64 65 SkPaint paint; 66 67 int y = kPad; 68 int x = kPad; 69 static const GrPrimitiveEdgeType kEdgeTypes[] = { 70 kFillAA_GrProcessorEdgeType, 71 kInverseFillAA_GrProcessorEdgeType, 72 }; 73 SkRect testBounds = SkRect::MakeIWH(fTestWidth, fTestHeight); 74 for (size_t et = 0; et < SK_ARRAY_COUNT(kEdgeTypes); ++et) { 75 GrPrimitiveEdgeType edgeType = kEdgeTypes[et]; 76 canvas->save(); 77 canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); 78 79 // Draw a background for the test case 80 SkPaint paint; 81 paint.setColor(SK_ColorWHITE); 82 canvas->drawRect(testBounds, paint); 83 84 GrPipelineBuilder pipelineBuilder; 85 pipelineBuilder.setXPFactory( 86 GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); 87 88 SkRRect rrect = fRRect; 89 rrect.offset(SkIntToScalar(x + kGap), SkIntToScalar(y + kGap)); 90 SkAutoTUnref<GrFragmentProcessor> fp(GrRRectEffect::Create(edgeType, rrect)); 91 SkASSERT(fp); 92 if (fp) { 93 pipelineBuilder.addCoverageFragmentProcessor(fp); 94 pipelineBuilder.setRenderTarget(rt); 95 96 SkRect bounds = testBounds; 97 bounds.offset(SkIntToScalar(x), SkIntToScalar(y)); 98 99 SkAutoTUnref<GrDrawBatch> batch( 100 GrRectBatchFactory::CreateNonAAFill(0xff000000, SkMatrix::I(), bounds, 101 nullptr, nullptr)); 102 drawContext->internal_drawBatch(pipelineBuilder, batch); 103 } 104 canvas->restore(); 105 x = x + fTestOffsetX; 106 } 107 } 108 109 private: 110 // pad between test cases 111 static const int kPad = 7; 112 // gap between rect for each case that is rendered and exterior of rrect 113 static const int kGap = 3; 114 115 SkRRect fRRect; 116 int fWidth; 117 int fHeight; 118 int fTestWidth; 119 int fTestHeight; 120 int fTestOffsetX; 121 int fTestOffsetY; 122 const char* fName; 123 typedef GM INHERITED; 124 }; 125 126 /////////////////////////////////////////////////////////////////////////////// 127 // This value is motivated by bug chromium:477684. It has to be large to cause overflow in 128 // the shader 129 static const int kSize = 700; 130 131 DEF_GM( return new BigRRectAAEffectGM (SkRRect::MakeRect(SkRect::MakeIWH(kSize, kSize)), "rect"); ) 132 DEF_GM( return new BigRRectAAEffectGM (SkRRect::MakeOval(SkRect::MakeIWH(kSize, kSize)), "circle"); ) 133 DEF_GM( return new BigRRectAAEffectGM (SkRRect::MakeOval(SkRect::MakeIWH(kSize - 1, kSize - 10)), "ellipse"); ) 134 // The next two have small linear segments between the corners 135 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"); ) 136 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"); ) 137 138 } 139 #endif 140