1 /* 2 * Copyright 2016 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 GL backend. 9 10 #include "gm/gm.h" 11 12 #ifdef SK_GL 13 #include "include/core/SkBitmap.h" 14 #include "include/core/SkCanvas.h" 15 #include "include/core/SkColor.h" 16 #include "include/core/SkImage.h" 17 #include "include/core/SkImageInfo.h" 18 #include "include/core/SkPaint.h" 19 #include "include/core/SkPoint.h" 20 #include "include/core/SkRect.h" 21 #include "include/core/SkRefCnt.h" 22 #include "include/core/SkScalar.h" 23 #include "include/core/SkShader.h" 24 #include "include/core/SkSize.h" 25 #include "include/core/SkString.h" 26 #include "include/core/SkTileMode.h" 27 #include "include/core/SkTypes.h" 28 #include "include/effects/SkGradientShader.h" 29 #include "include/gpu/ganesh/GrBackendSurface.h" 30 #include "include/gpu/ganesh/GrDirectContext.h" 31 #include "include/gpu/ganesh/GrTypes.h" 32 #include "include/gpu/ganesh/SkImageGanesh.h" 33 #include "include/gpu/ganesh/gl/GrGLBackendSurface.h" 34 #include "src/core/SkAutoPixmapStorage.h" 35 #include "src/gpu/ganesh/GrDirectContextPriv.h" 36 #include "src/gpu/ganesh/GrGpu.h" 37 #include "src/gpu/ganesh/gl/GrGLCaps.h" 38 #include "src/gpu/ganesh/gl/GrGLDefines.h" 39 40 #include <algorithm> 41 #include <cstdint> 42 #include <memory> 43 44 namespace skiagm { 45 class RectangleTexture : public GM { 46 public: RectangleTexture()47 RectangleTexture() { 48 this->setBGColor(0xFFFFFFFF); 49 } 50 51 private: 52 enum class ImageType { 53 kGradientCircle, 54 k2x2 55 }; 56 getName() const57 SkString getName() const override { return SkString("rectangle_texture"); } 58 getISize()59 SkISize getISize() override { return SkISize::Make(1180, 710); } 60 makeImagePixels(int size,ImageType type)61 SkBitmap makeImagePixels(int size, ImageType type) { 62 auto ii = SkImageInfo::Make(size, size, kRGBA_8888_SkColorType, kOpaque_SkAlphaType); 63 switch (type) { 64 case ImageType::kGradientCircle: { 65 SkBitmap bmp; 66 bmp.allocPixels(ii); 67 SkPaint paint; 68 SkCanvas canvas(bmp); 69 SkPoint pts[] = {{0, 0}, {0, SkIntToScalar(size)}}; 70 SkColor colors0[] = {0xFF1060B0, 0xFF102030}; 71 paint.setShader( 72 SkGradientShader::MakeLinear(pts, colors0, nullptr, 2, SkTileMode::kClamp)); 73 canvas.drawPaint(paint); 74 SkColor colors1[] = {0xFFA07010, 0xFFA02080}; 75 paint.setAntiAlias(true); 76 paint.setShader( 77 SkGradientShader::MakeLinear(pts, colors1, nullptr, 2, SkTileMode::kClamp)); 78 canvas.drawCircle(size/2.f, size/2.f, 2.f*size/5, paint); 79 return bmp; 80 } 81 case ImageType::k2x2: { 82 SkBitmap bmp; 83 bmp.allocPixels(ii); 84 *bmp.getAddr32(0, 0) = 0xFF0000FF; 85 *bmp.getAddr32(1, 0) = 0xFF00FF00; 86 *bmp.getAddr32(0, 1) = 0xFFFF0000; 87 *bmp.getAddr32(1, 1) = 0xFFFFFFFF; 88 return bmp; 89 } 90 } 91 SkUNREACHABLE; 92 } 93 createRectangleTextureImg(GrDirectContext * dContext,GrSurfaceOrigin origin,const SkBitmap content)94 sk_sp<SkImage> createRectangleTextureImg(GrDirectContext* dContext, GrSurfaceOrigin origin, 95 const SkBitmap content) { 96 SkASSERT(content.colorType() == kRGBA_8888_SkColorType); 97 auto format = GrBackendFormats::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_RECTANGLE); 98 auto bet = dContext->createBackendTexture(content.width(), 99 content.height(), 100 format, 101 skgpu::Mipmapped::kNo, 102 GrRenderable::kNo, 103 GrProtected::kNo, 104 /*label=*/"CreateRectangleTextureImage"); 105 if (!bet.isValid()) { 106 return nullptr; 107 } 108 if (!dContext->updateBackendTexture(bet, content.pixmap(), origin, nullptr, nullptr)) { 109 dContext->deleteBackendTexture(bet); 110 } 111 return SkImages::AdoptTextureFrom(dContext, bet, origin, kRGBA_8888_SkColorType); 112 } 113 onGpuSetup(SkCanvas * canvas,SkString * errorMsg,GraphiteTestContext *)114 DrawResult onGpuSetup(SkCanvas* canvas, SkString* errorMsg, GraphiteTestContext*) override { 115 auto context = GrAsDirectContext(canvas->recordingContext()); 116 if (!context || context->abandoned()) { 117 return DrawResult::kSkip; 118 } 119 120 if (context->backend() != GrBackendApi::kOpenGL_GrBackend || 121 !static_cast<const GrGLCaps*>(context->priv().caps())->rectangleTextureSupport()) { 122 *errorMsg = "This GM requires an OpenGL context that supports texture rectangles."; 123 return DrawResult::kSkip; 124 } 125 126 auto gradCircle = this->makeImagePixels(50, ImageType::kGradientCircle); 127 128 fGradImgs[0] = this->createRectangleTextureImg(context, kTopLeft_GrSurfaceOrigin, 129 gradCircle); 130 fGradImgs[1] = this->createRectangleTextureImg(context, kBottomLeft_GrSurfaceOrigin, 131 gradCircle); 132 SkASSERT(SkToBool(fGradImgs[0]) == SkToBool(fGradImgs[1])); 133 if (!fGradImgs[0]) { 134 *errorMsg = "Could not create gradient rectangle texture images."; 135 return DrawResult::kFail; 136 } 137 138 fSmallImg = this->createRectangleTextureImg(context, kTopLeft_GrSurfaceOrigin, 139 this->makeImagePixels(2, ImageType::k2x2)); 140 if (!fSmallImg) { 141 *errorMsg = "Could not create 2x2 rectangle texture image."; 142 return DrawResult::kFail; 143 } 144 145 return DrawResult::kOk; 146 } 147 onGpuTeardown()148 void onGpuTeardown() override { 149 fGradImgs[0] = fGradImgs[1] = nullptr; 150 fSmallImg = nullptr; 151 } 152 onDraw(SkCanvas * canvas,SkString * errorMsg)153 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override { 154 SkASSERT(fGradImgs[0] && fGradImgs[1] && fSmallImg); 155 156 static constexpr SkScalar kPad = 5.f; 157 158 const SkSamplingOptions kSamplings[] = { 159 SkSamplingOptions(SkFilterMode::kNearest), 160 SkSamplingOptions(SkFilterMode::kLinear), 161 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), 162 SkSamplingOptions(SkCubicResampler::Mitchell()), 163 }; 164 165 constexpr SkScalar kScales[] = {1.0f, 1.2f, 0.75f}; 166 167 canvas->translate(kPad, kPad); 168 for (size_t i = 0; i < kNumGradImages; ++i) { 169 auto img = fGradImgs[i]; 170 int w = img->width(); 171 int h = img->height(); 172 for (auto scale : kScales) { 173 canvas->save(); 174 canvas->scale(scale, scale); 175 for (auto s : kSamplings) { 176 // drawImage 177 canvas->drawImage(img, 0, 0, s); 178 canvas->translate(w + kPad, 0); 179 180 // clamp/clamp shader 181 SkPaint clampPaint; 182 clampPaint.setShader(fGradImgs[i]->makeShader(s)); 183 canvas->drawRect(SkRect::MakeWH(1.5f*w, 1.5f*h), clampPaint); 184 canvas->translate(1.5f*w + kPad, 0); 185 186 // repeat/mirror shader 187 SkPaint repeatPaint; 188 repeatPaint.setShader(fGradImgs[i]->makeShader(SkTileMode::kRepeat, 189 SkTileMode::kMirror, 190 s)); 191 canvas->drawRect(SkRect::MakeWH(1.5f*w, 1.5f*h), repeatPaint); 192 canvas->translate(1.5f*w + kPad, 0); 193 194 // drawImageRect with kStrict 195 auto srcRect = SkRect::MakeXYWH(.25f*w, .25f*h, .50f*w, .50f*h); 196 auto dstRect = SkRect::MakeXYWH( 0, 0, .50f*w, .50f*h); 197 canvas->drawImageRect(fGradImgs[i], srcRect, dstRect, s, nullptr, 198 SkCanvas::kStrict_SrcRectConstraint); 199 canvas->translate(.5f*w + kPad, 0); 200 } 201 canvas->restore(); 202 canvas->translate(0, kPad + 1.5f*h*scale); 203 } 204 } 205 206 static constexpr SkScalar kOutset = 25.f; 207 canvas->translate(kOutset, kOutset); 208 auto dstRect = SkRect::Make(fSmallImg->dimensions()).makeOutset(kOutset, kOutset); 209 210 const SkSamplingOptions gSamplings[] = { 211 SkSamplingOptions(SkFilterMode::kNearest), 212 SkSamplingOptions(SkFilterMode::kLinear), 213 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), 214 SkSamplingOptions(SkCubicResampler::Mitchell()), 215 }; 216 217 for (const auto& sampling : gSamplings) { 218 if (!sampling.useCubic && sampling.mipmap != SkMipmapMode::kNone) { 219 // Medium is the same as Low for upscaling. 220 continue; 221 } 222 canvas->save(); 223 for (int ty = 0; ty < kSkTileModeCount; ++ty) { 224 canvas->save(); 225 for (int tx = 0; tx < kSkTileModeCount; ++tx) { 226 SkMatrix lm; 227 lm.setRotate(45.f, 1, 1); 228 lm.postScale(6.5f, 6.5f); 229 SkPaint paint; 230 paint.setShader(fSmallImg->makeShader(static_cast<SkTileMode>(tx), 231 static_cast<SkTileMode>(ty), 232 sampling, 233 lm)); 234 canvas->drawRect(dstRect, paint); 235 canvas->translate(dstRect.width() + kPad, 0); 236 } 237 canvas->restore(); 238 canvas->translate(0, dstRect.height() + kPad); 239 } 240 canvas->restore(); 241 canvas->translate((dstRect.width() + kPad)*kSkTileModeCount, 0); 242 } 243 244 return DrawResult::kOk; 245 } 246 247 private: 248 static const int kNumGradImages = 2; 249 250 sk_sp<SkImage> fGradImgs[kNumGradImages]; 251 sk_sp<SkImage> fSmallImg; 252 253 using INHERITED = GM; 254 }; 255 256 DEF_GM(return new RectangleTexture;) 257 } // namespace skiagm 258 #endif 259