1 /* 2 * Copyright 2014 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.h" 11 12 #include "GrContext.h" 13 #include "GrContextPriv.h" 14 #include "GrProxyProvider.h" 15 #include "GrRenderTargetContextPriv.h" 16 #include "SkGradientShader.h" 17 #include "SkImage.h" 18 #include "SkImage_Base.h" 19 #include "SkSurface.h" 20 #include "effects/GrTextureDomain.h" 21 #include "ops/GrDrawOp.h" 22 #include "ops/GrFillRectOp.h" 23 24 namespace skiagm { 25 /** 26 * This GM directly exercises GrTextureDomainEffect. 27 */ 28 class TextureDomainEffect : public GpuGM { 29 public: 30 TextureDomainEffect(GrSamplerState::Filter filter) 31 : fFilter(filter) { 32 this->setBGColor(0xFFFFFFFF); 33 } 34 35 protected: 36 SkString onShortName() override { 37 SkString name("texture_domain_effect"); 38 if (fFilter == GrSamplerState::Filter::kBilerp) { 39 name.append("_bilerp"); 40 } else if (fFilter == GrSamplerState::Filter::kMipMap) { 41 name.append("_mipmap"); 42 } 43 return name; 44 } 45 46 SkISize onISize() override { 47 const SkScalar canvasWidth = kDrawPad + 48 (kTargetWidth + 2 * kDrawPad) * GrTextureDomain::kModeCount + 49 kTestPad * GrTextureDomain::kModeCount; 50 return SkISize::Make(SkScalarCeilToInt(canvasWidth), 800); 51 } 52 53 void onOnceBeforeDraw() override { 54 // TODO: do this with gpu backend 55 SkImageInfo ii = SkImageInfo::Make(kTargetWidth, kTargetHeight, kN32_SkColorType, 56 kPremul_SkAlphaType); 57 auto surface = SkSurface::MakeRaster(ii); 58 SkCanvas* canvas = surface->getCanvas(); 59 canvas->clear(0x00000000); 60 SkPaint paint; 61 62 SkColor colors1[] = { SK_ColorCYAN, SK_ColorLTGRAY, SK_ColorGRAY }; 63 paint.setShader(SkGradientShader::MakeSweep(65.f, 75.f, colors1, nullptr, 64 SK_ARRAY_COUNT(colors1))); 65 canvas->drawOval(SkRect::MakeXYWH(-5.f, -5.f, kTargetWidth + 10.f, kTargetHeight + 10.f), 66 paint); 67 68 SkColor colors2[] = { SK_ColorMAGENTA, SK_ColorLTGRAY, SK_ColorYELLOW }; 69 paint.setShader(SkGradientShader::MakeSweep(45.f, 55.f, colors2, nullptr, 70 SK_ARRAY_COUNT(colors2))); 71 paint.setBlendMode(SkBlendMode::kDarken); 72 canvas->drawOval(SkRect::MakeXYWH(-5.f, -5.f, kTargetWidth + 10.f, kTargetHeight + 10.f), 73 paint); 74 75 SkColor colors3[] = { SK_ColorBLUE, SK_ColorLTGRAY, SK_ColorGREEN }; 76 paint.setShader(SkGradientShader::MakeSweep(25.f, 35.f, colors3, nullptr, 77 SK_ARRAY_COUNT(colors3))); 78 paint.setBlendMode(SkBlendMode::kLighten); 79 canvas->drawOval(SkRect::MakeXYWH(-5.f, -5.f, kTargetWidth + 10.f, kTargetHeight + 10.f), 80 paint); 81 82 fImage = surface->makeImageSnapshot(); 83 } 84 85 DrawResult onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext, 86 SkCanvas* canvas, SkString* errorMsg) override { 87 GrProxyProvider* proxyProvider = context->priv().proxyProvider(); 88 sk_sp<GrTextureProxy> proxy; 89 if (fFilter == GrSamplerState::Filter::kMipMap) { 90 SkBitmap copy; 91 SkImageInfo info = as_IB(fImage)->onImageInfo().makeColorType(kN32_SkColorType); 92 if (!copy.tryAllocPixels(info) || !fImage->readPixels(copy.pixmap(), 0, 0)) { 93 *errorMsg = "Failed to read pixels."; 94 return DrawResult::kFail; 95 } 96 proxy = proxyProvider->createMipMapProxyFromBitmap(copy); 97 } else { 98 proxy = proxyProvider->createTextureProxy( 99 fImage, kNone_GrSurfaceFlags, 1, SkBudgeted::kYes, SkBackingFit::kExact); 100 } 101 if (!proxy) { 102 *errorMsg = "Failed to create proxy."; 103 return DrawResult::kFail; 104 } 105 106 SkTArray<SkMatrix> textureMatrices; 107 textureMatrices.push_back() = SkMatrix::I(); 108 textureMatrices.push_back() = SkMatrix::MakeScale(1.5f, 0.85f); 109 textureMatrices.push_back(); 110 textureMatrices.back().setRotate(45.f, proxy->width() / 2.f, proxy->height() / 2.f); 111 112 const SkIRect texelDomains[] = { 113 fImage->bounds(), 114 SkIRect::MakeXYWH(fImage->width() / 4 - 1, fImage->height() / 4 - 1, 115 fImage->width() / 2 + 2, fImage->height() / 2 + 2), 116 }; 117 118 SkRect renderRect = SkRect::Make(fImage->bounds()); 119 renderRect.outset(kDrawPad, kDrawPad); 120 121 SkScalar y = kDrawPad + kTestPad; 122 for (int tm = 0; tm < textureMatrices.count(); ++tm) { 123 for (size_t d = 0; d < SK_ARRAY_COUNT(texelDomains); ++d) { 124 SkScalar x = kDrawPad + kTestPad; 125 for (int m = 0; m < GrTextureDomain::kModeCount; ++m) { 126 GrTextureDomain::Mode mode = (GrTextureDomain::Mode) m; 127 if (fFilter != GrSamplerState::Filter::kNearest && 128 mode == GrTextureDomain::kRepeat_Mode) { 129 // Repeat mode doesn't produce correct results with bilerp filtering 130 continue; 131 } 132 133 GrPaint grPaint; 134 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); 135 auto fp = GrTextureDomainEffect::Make( 136 proxy, textureMatrices[tm], 137 GrTextureDomain::MakeTexelDomain(texelDomains[d], mode), 138 mode, fFilter); 139 140 if (!fp) { 141 continue; 142 } 143 const SkMatrix viewMatrix = SkMatrix::MakeTrans(x, y); 144 grPaint.addColorFragmentProcessor(std::move(fp)); 145 renderTargetContext->priv().testingOnly_addDrawOp( 146 GrFillRectOp::Make(context, std::move(grPaint), GrAAType::kNone, 147 viewMatrix, renderRect)); 148 x += renderRect.width() + kTestPad; 149 } 150 y += renderRect.height() + kTestPad; 151 } 152 } 153 return DrawResult::kOk; 154 } 155 156 private: 157 static constexpr SkScalar kDrawPad = 10.f; 158 static constexpr SkScalar kTestPad = 10.f; 159 static constexpr int kTargetWidth = 100; 160 static constexpr int kTargetHeight = 100; 161 sk_sp<SkImage> fImage; 162 GrSamplerState::Filter fFilter; 163 164 typedef GM INHERITED; 165 }; 166 167 DEF_GM(return new TextureDomainEffect(GrSamplerState::Filter::kNearest);) 168 DEF_GM(return new TextureDomainEffect(GrSamplerState::Filter::kBilerp);) 169 DEF_GM(return new TextureDomainEffect(GrSamplerState::Filter::kMipMap);) 170 171 } 172