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 GM { 29 public: TextureDomainEffect(GrSamplerState::Filter filter)30 TextureDomainEffect(GrSamplerState::Filter filter) 31 : fFilter(filter) { 32 this->setBGColor(0xFFFFFFFF); 33 } 34 35 protected: onShortName()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 onISize()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 onOnceBeforeDraw()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 onDraw(SkCanvas * canvas)85 void onDraw(SkCanvas* canvas) override { 86 GrRenderTargetContext* renderTargetContext = 87 canvas->internal_private_accessTopLayerRenderTargetContext(); 88 if (!renderTargetContext) { 89 skiagm::GM::DrawGpuOnlyMessage(canvas); 90 return; 91 } 92 93 GrContext* context = canvas->getGrContext(); 94 if (!context) { 95 return; 96 } 97 98 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 99 sk_sp<GrTextureProxy> proxy; 100 if (fFilter == GrSamplerState::Filter::kMipMap) { 101 SkBitmap copy; 102 SkImageInfo info = as_IB(fImage)->onImageInfo().makeColorType(kN32_SkColorType); 103 if (!copy.tryAllocPixels(info) || !fImage->readPixels(copy.pixmap(), 0, 0)) { 104 return; 105 } 106 proxy = proxyProvider->createMipMapProxyFromBitmap(copy); 107 } else { 108 proxy = proxyProvider->createTextureProxy( 109 fImage, kNone_GrSurfaceFlags, 1, SkBudgeted::kYes, SkBackingFit::kExact); 110 } 111 if (!proxy) { 112 return; 113 } 114 115 SkTArray<SkMatrix> textureMatrices; 116 textureMatrices.push_back() = SkMatrix::I(); 117 textureMatrices.push_back() = SkMatrix::MakeScale(1.5f, 0.85f); 118 textureMatrices.push_back(); 119 textureMatrices.back().setRotate(45.f, proxy->width() / 2.f, proxy->height() / 2.f); 120 121 const SkIRect texelDomains[] = { 122 fImage->bounds(), 123 SkIRect::MakeXYWH(fImage->width() / 4 - 1, fImage->height() / 4 - 1, 124 fImage->width() / 2 + 2, fImage->height() / 2 + 2), 125 }; 126 127 SkRect renderRect = SkRect::Make(fImage->bounds()); 128 renderRect.outset(kDrawPad, kDrawPad); 129 130 SkScalar y = kDrawPad + kTestPad; 131 for (int tm = 0; tm < textureMatrices.count(); ++tm) { 132 for (size_t d = 0; d < SK_ARRAY_COUNT(texelDomains); ++d) { 133 SkScalar x = kDrawPad + kTestPad; 134 for (int m = 0; m < GrTextureDomain::kModeCount; ++m) { 135 GrTextureDomain::Mode mode = (GrTextureDomain::Mode) m; 136 if (fFilter != GrSamplerState::Filter::kNearest && 137 mode == GrTextureDomain::kRepeat_Mode) { 138 // Repeat mode doesn't produce correct results with bilerp filtering 139 continue; 140 } 141 142 GrPaint grPaint; 143 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); 144 auto fp = GrTextureDomainEffect::Make( 145 proxy, textureMatrices[tm], 146 GrTextureDomain::MakeTexelDomain(texelDomains[d], mode), 147 mode, fFilter); 148 149 if (!fp) { 150 continue; 151 } 152 const SkMatrix viewMatrix = SkMatrix::MakeTrans(x, y); 153 grPaint.addColorFragmentProcessor(std::move(fp)); 154 renderTargetContext->priv().testingOnly_addDrawOp( 155 GrFillRectOp::Make(context, std::move(grPaint), GrAAType::kNone, 156 viewMatrix, renderRect)); 157 x += renderRect.width() + kTestPad; 158 } 159 y += renderRect.height() + kTestPad; 160 } 161 } 162 } 163 164 private: 165 static constexpr SkScalar kDrawPad = 10.f; 166 static constexpr SkScalar kTestPad = 10.f; 167 static constexpr int kTargetWidth = 100; 168 static constexpr int kTargetHeight = 100; 169 sk_sp<SkImage> fImage; 170 GrSamplerState::Filter fFilter; 171 172 typedef GM INHERITED; 173 }; 174 175 DEF_GM(return new TextureDomainEffect(GrSamplerState::Filter::kNearest);) 176 DEF_GM(return new TextureDomainEffect(GrSamplerState::Filter::kBilerp);) 177 DEF_GM(return new TextureDomainEffect(GrSamplerState::Filter::kMipMap);) 178 179 } 180