| Robert Phillips | ec32534 | 2017-10-30 18:02:48 +0000 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright 2017 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 "Test.h" | 
| Mike Reed | 75ae421 | 2018-01-23 11:24:08 -0500 | [diff] [blame] | 9 | #include "SkBitmap.h" | 
| Robert Phillips | ec32534 | 2017-10-30 18:02:48 +0000 | [diff] [blame] | 10 |  | 
 | 11 | #if SK_SUPPORT_GPU | 
 | 12 | #include "GrClip.h" | 
 | 13 | #include "GrRenderTargetContext.h" | 
 | 14 | #include "GrStyle.h" | 
 | 15 | #include "GrTypesPriv.h" | 
 | 16 |  | 
 | 17 | #include "effects/GrConstColorProcessor.h" | 
 | 18 |  | 
 | 19 | static void allow_default_and_msaa(GrContextOptions* options) { | 
 | 20 |     options->fGpuPathRenderers = GpuPathRenderers::kMSAA; | 
 | 21 | } | 
 | 22 |  | 
 | 23 | static void only_allow_default(GrContextOptions* options) { | 
 | 24 |     options->fGpuPathRenderers = GpuPathRenderers::kNone; | 
 | 25 | } | 
 | 26 |  | 
 | 27 | static SkBitmap read_back(GrRenderTargetContext* rtc, int width, int height) { | 
 | 28 |  | 
 | 29 |     SkImageInfo dstII = SkImageInfo::MakeN32Premul(width, height); | 
 | 30 |  | 
 | 31 |     SkBitmap bm; | 
 | 32 |     bm.allocPixels(dstII); | 
 | 33 |  | 
 | 34 |     rtc->readPixels(dstII, bm.getAddr(0, 0), bm.rowBytes(), 0, 0, 0); | 
 | 35 |  | 
 | 36 |     return bm; | 
 | 37 | } | 
 | 38 |  | 
 | 39 | static SkPath make_path(const SkRect& outer, int inset, SkPath::FillType fill) { | 
 | 40 |     SkPath p; | 
 | 41 |  | 
 | 42 |     p.addRect(outer, SkPath::kCW_Direction); | 
 | 43 |     p.addRect(outer.makeInset(inset, inset), SkPath::kCCW_Direction); | 
 | 44 |     p.setFillType(fill); | 
 | 45 |     return p; | 
 | 46 | } | 
 | 47 |  | 
 | 48 |  | 
 | 49 | static const int kBigSize = 64; // This should be a power of 2 | 
 | 50 | static const int kPad = 3; | 
 | 51 |  | 
 | 52 | // From crbug.com/769898: | 
 | 53 | //   create an approx fit render target context that will have extra space (i.e., npot) | 
 | 54 | //   draw an inverse wound concave path into it - forcing use of the stencil-using path renderer | 
 | 55 | //   throw the RTC away so the backing GrSurface/GrStencilBuffer can be reused | 
 | 56 | //   create a new render target context that will reuse the prior GrSurface | 
 | 57 | //   draw a normally wound concave path that touches outside of the approx fit RTC's content rect | 
 | 58 | // | 
 | 59 | // When the bug manifests the GrDefaultPathRenderer/GrMSAAPathRenderer is/was leaving the stencil | 
 | 60 | // buffer outside of the first content rect in a bad state and the second draw would be incorrect. | 
 | 61 |  | 
 | 62 | static void run_test(GrContext* ctx, skiatest::Reporter* reporter) { | 
 | 63 |     SkPath invPath = make_path(SkRect::MakeXYWH(0, 0, kBigSize, kBigSize), | 
 | 64 |                                kBigSize/2-1, SkPath::kInverseWinding_FillType); | 
 | 65 |     SkPath path = make_path(SkRect::MakeXYWH(0, 0, kBigSize, kBigSize), | 
 | 66 |                             kPad, SkPath::kWinding_FillType); | 
 | 67 |  | 
 | 68 |     GrStyle style(SkStrokeRec::kFill_InitStyle); | 
 | 69 |  | 
 | 70 |     { | 
| Robert Phillips | 0c4b7b1 | 2018-03-06 08:20:37 -0500 | [diff] [blame] | 71 |         auto rtc =  ctx->contextPriv().makeDeferredRenderTargetContext( | 
 | 72 |                                                          SkBackingFit::kApprox, | 
| Robert Phillips | ec32534 | 2017-10-30 18:02:48 +0000 | [diff] [blame] | 73 |                                                          kBigSize/2+1, kBigSize/2+1, | 
 | 74 |                                                          kRGBA_8888_GrPixelConfig, nullptr); | 
 | 75 |  | 
| Chris Dalton | 344e903 | 2017-12-11 15:42:09 -0700 | [diff] [blame] | 76 |         rtc->clear(nullptr, GrColorPackRGBA(0x0, 0x0, 0x0, 0xFF), | 
 | 77 |                    GrRenderTargetContext::CanClearFullscreen::kYes); | 
| Robert Phillips | ec32534 | 2017-10-30 18:02:48 +0000 | [diff] [blame] | 78 |  | 
 | 79 |         GrPaint paint; | 
 | 80 |  | 
 | 81 |         const GrColor4f color = { 1.0f, 0.0f, 0.0f, 1.0f }; | 
| Ethan Nicholas | e9d172a | 2017-11-20 12:12:24 -0500 | [diff] [blame] | 82 |         auto fp = GrConstColorProcessor::Make(color, GrConstColorProcessor::InputMode::kIgnore); | 
| Robert Phillips | ec32534 | 2017-10-30 18:02:48 +0000 | [diff] [blame] | 83 |         paint.addColorFragmentProcessor(std::move(fp)); | 
 | 84 |  | 
 | 85 |         rtc->drawPath(GrNoClip(), std::move(paint), GrAA::kNo, | 
 | 86 |                       SkMatrix::I(), invPath, style); | 
 | 87 |  | 
 | 88 |         rtc->prepareForExternalIO(0, nullptr); | 
 | 89 |     } | 
 | 90 |  | 
 | 91 |     { | 
| Robert Phillips | 0c4b7b1 | 2018-03-06 08:20:37 -0500 | [diff] [blame] | 92 |         auto rtc = ctx->contextPriv().makeDeferredRenderTargetContext( | 
 | 93 |                                                         SkBackingFit::kExact, kBigSize, kBigSize, | 
| Robert Phillips | ec32534 | 2017-10-30 18:02:48 +0000 | [diff] [blame] | 94 |                                                         kRGBA_8888_GrPixelConfig, nullptr); | 
 | 95 |  | 
| Chris Dalton | 344e903 | 2017-12-11 15:42:09 -0700 | [diff] [blame] | 96 |         rtc->clear(nullptr, GrColorPackRGBA(0x0, 0x0, 0x0, 0xFF), | 
 | 97 |                    GrRenderTargetContext::CanClearFullscreen::kYes); | 
| Robert Phillips | ec32534 | 2017-10-30 18:02:48 +0000 | [diff] [blame] | 98 |  | 
 | 99 |         GrPaint paint; | 
 | 100 |  | 
 | 101 |         const GrColor4f color = { 0.0f, 1.0f, 0.0f, 1.0f }; | 
| Ethan Nicholas | e9d172a | 2017-11-20 12:12:24 -0500 | [diff] [blame] | 102 |         auto fp = GrConstColorProcessor::Make(color, GrConstColorProcessor::InputMode::kIgnore); | 
| Robert Phillips | ec32534 | 2017-10-30 18:02:48 +0000 | [diff] [blame] | 103 |         paint.addColorFragmentProcessor(std::move(fp)); | 
 | 104 |  | 
 | 105 |         rtc->drawPath(GrNoClip(), std::move(paint), GrAA::kNo, | 
 | 106 |                       SkMatrix::I(), path, style); | 
 | 107 |  | 
 | 108 |         SkBitmap bm = read_back(rtc.get(), kBigSize, kBigSize); | 
 | 109 |  | 
 | 110 |         bool correct = true; | 
 | 111 |         for (int y = kBigSize/2+1; y < kBigSize-kPad-1 && correct; ++y) { | 
 | 112 |             for (int x = kPad+1; x < kBigSize-kPad-1 && correct; ++x) { | 
 | 113 |                 correct = bm.getColor(x, y) == SK_ColorBLACK; | 
 | 114 |                 REPORTER_ASSERT(reporter, correct); | 
 | 115 |             } | 
 | 116 |         } | 
 | 117 |     } | 
 | 118 |  | 
 | 119 | } | 
 | 120 |  | 
 | 121 | DEF_GPUTEST_FOR_CONTEXTS(GrDefaultPathRendererTest, | 
 | 122 |                          sk_gpu_test::GrContextFactory::IsRenderingContext, | 
 | 123 |                          reporter, ctxInfo, only_allow_default) { | 
 | 124 |     GrContext* ctx = ctxInfo.grContext(); | 
 | 125 |  | 
 | 126 |     run_test(ctx, reporter); | 
 | 127 | } | 
 | 128 |  | 
 | 129 | DEF_GPUTEST_FOR_CONTEXTS(GrMSAAPathRendererTest, | 
 | 130 |                          sk_gpu_test::GrContextFactory::IsRenderingContext, | 
 | 131 |                          reporter, ctxInfo, allow_default_and_msaa) { | 
 | 132 |     GrContext* ctx = ctxInfo.grContext(); | 
 | 133 |  | 
 | 134 |     if (!ctx->caps()->sampleShadingSupport()) {   // The MSAAPathRenderer requires this | 
 | 135 |         return; | 
 | 136 |     } | 
 | 137 |  | 
 | 138 |     run_test(ctx, reporter); | 
 | 139 | } | 
 | 140 |  | 
 | 141 | #endif |