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/GrBackendSurface.h" 30 #include "include/gpu/GrDirectContext.h" 31 #include "include/gpu/GrTypes.h" 32 #include "src/core/SkAutoPixmapStorage.h" 33 #include "src/gpu/GrDirectContextPriv.h" 34 #include "src/gpu/GrGpu.h" 35 #include "src/gpu/gl/GrGLCaps.h" 36 #include "src/gpu/gl/GrGLDefines.h" 37 38 #include <algorithm> 39 #include <cstdint> 40 #include <memory> 41 42 namespace skiagm { 43 class RectangleTexture : public GM { 44 public: RectangleTexture()45 RectangleTexture() { 46 this->setBGColor(0xFFFFFFFF); 47 } 48 49 private: 50 enum class ImageType { 51 kGradientCircle, 52 k2x2 53 }; 54 onShortName()55 SkString onShortName() override { 56 return SkString("rectangle_texture"); 57 } 58 onISize()59 SkISize onISize() 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 = GrBackendFormat::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_RECTANGLE); 98 auto bet = dContext->createBackendTexture(content.width(), content.height(), format, 99 GrMipmapped::kNo, GrRenderable::kNo); 100 if (!bet.isValid()) { 101 return nullptr; 102 } 103 if (!dContext->updateBackendTexture(bet, content.pixmap(), origin, nullptr, nullptr)) { 104 dContext->deleteBackendTexture(bet); 105 } 106 return SkImage::MakeFromAdoptedTexture(dContext, bet, origin, kRGBA_8888_SkColorType); 107 } 108 onGpuSetup(GrDirectContext * context,SkString * errorMsg)109 DrawResult onGpuSetup(GrDirectContext* context, SkString* errorMsg) override { 110 if (!context || context->abandoned()) { 111 return DrawResult::kSkip; 112 } 113 114 if (context->backend() != GrBackendApi::kOpenGL_GrBackend || 115 !static_cast<const GrGLCaps*>(context->priv().caps())->rectangleTextureSupport()) { 116 *errorMsg = "This GM requires an OpenGL context that supports texture rectangles."; 117 return DrawResult::kSkip; 118 } 119 120 auto gradCircle = this->makeImagePixels(50, ImageType::kGradientCircle); 121 122 fGradImgs[0] = this->createRectangleTextureImg(context, kTopLeft_GrSurfaceOrigin, 123 gradCircle); 124 fGradImgs[1] = this->createRectangleTextureImg(context, kBottomLeft_GrSurfaceOrigin, 125 gradCircle); 126 SkASSERT(SkToBool(fGradImgs[0]) == SkToBool(fGradImgs[1])); 127 if (!fGradImgs[0]) { 128 *errorMsg = "Could not create gradient rectangle texture images."; 129 return DrawResult::kFail; 130 } 131 132 fSmallImg = this->createRectangleTextureImg(context, kTopLeft_GrSurfaceOrigin, 133 this->makeImagePixels(2, ImageType::k2x2)); 134 if (!fSmallImg) { 135 *errorMsg = "Could not create 2x2 rectangle texture image."; 136 return DrawResult::kFail; 137 } 138 139 return DrawResult::kOk; 140 } 141 onGpuTeardown()142 void onGpuTeardown() override { 143 fGradImgs[0] = fGradImgs[1] = nullptr; 144 fSmallImg = nullptr; 145 } 146 onDraw(SkCanvas * canvas,SkString * errorMsg)147 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override { 148 SkASSERT(fGradImgs[0] && fGradImgs[1] && fSmallImg); 149 150 static constexpr SkScalar kPad = 5.f; 151 152 const SkSamplingOptions kSamplings[] = { 153 SkSamplingOptions(SkFilterMode::kNearest), 154 SkSamplingOptions(SkFilterMode::kLinear), 155 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), 156 SkSamplingOptions(SkCubicResampler::Mitchell()), 157 }; 158 159 constexpr SkScalar kScales[] = {1.0f, 1.2f, 0.75f}; 160 161 canvas->translate(kPad, kPad); 162 for (size_t i = 0; i < kNumGradImages; ++i) { 163 auto img = fGradImgs[i]; 164 int w = img->width(); 165 int h = img->height(); 166 for (auto scale : kScales) { 167 canvas->save(); 168 canvas->scale(scale, scale); 169 for (auto s : kSamplings) { 170 // drawImage 171 canvas->drawImage(img, 0, 0, s); 172 canvas->translate(w + kPad, 0); 173 174 // clamp/clamp shader 175 SkPaint clampPaint; 176 clampPaint.setShader(fGradImgs[i]->makeShader(s)); 177 canvas->drawRect(SkRect::MakeWH(1.5f*w, 1.5f*h), clampPaint); 178 canvas->translate(1.5f*w + kPad, 0); 179 180 // repeat/mirror shader 181 SkPaint repeatPaint; 182 repeatPaint.setShader(fGradImgs[i]->makeShader(SkTileMode::kRepeat, 183 SkTileMode::kMirror, 184 s)); 185 canvas->drawRect(SkRect::MakeWH(1.5f*w, 1.5f*h), repeatPaint); 186 canvas->translate(1.5f*w + kPad, 0); 187 188 // drawImageRect with kStrict 189 auto srcRect = SkRect::MakeXYWH(.25f*w, .25f*h, .50f*w, .50f*h); 190 auto dstRect = SkRect::MakeXYWH( 0, 0, .50f*w, .50f*h); 191 canvas->drawImageRect(fGradImgs[i], srcRect, dstRect, s, nullptr, 192 SkCanvas::kStrict_SrcRectConstraint); 193 canvas->translate(.5f*w + kPad, 0); 194 } 195 canvas->restore(); 196 canvas->translate(0, kPad + 1.5f*h*scale); 197 } 198 } 199 200 static constexpr SkScalar kOutset = 25.f; 201 canvas->translate(kOutset, kOutset); 202 auto dstRect = SkRect::Make(fSmallImg->dimensions()).makeOutset(kOutset, kOutset); 203 204 const SkSamplingOptions gSamplings[] = { 205 SkSamplingOptions(SkFilterMode::kNearest), 206 SkSamplingOptions(SkFilterMode::kLinear), 207 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), 208 SkSamplingOptions(SkCubicResampler::Mitchell()), 209 }; 210 211 for (const auto& sampling : gSamplings) { 212 if (!sampling.useCubic && sampling.mipmap != SkMipmapMode::kNone) { 213 // Medium is the same as Low for upscaling. 214 continue; 215 } 216 canvas->save(); 217 for (int ty = 0; ty < kSkTileModeCount; ++ty) { 218 canvas->save(); 219 for (int tx = 0; tx < kSkTileModeCount; ++tx) { 220 SkMatrix lm; 221 lm.setRotate(45.f, 1, 1); 222 lm.postScale(6.5f, 6.5f); 223 SkPaint paint; 224 paint.setShader(fSmallImg->makeShader(static_cast<SkTileMode>(tx), 225 static_cast<SkTileMode>(ty), 226 sampling, 227 lm)); 228 canvas->drawRect(dstRect, paint); 229 canvas->translate(dstRect.width() + kPad, 0); 230 } 231 canvas->restore(); 232 canvas->translate(0, dstRect.height() + kPad); 233 } 234 canvas->restore(); 235 canvas->translate((dstRect.width() + kPad)*kSkTileModeCount, 0); 236 } 237 238 return DrawResult::kOk; 239 } 240 241 private: 242 static const int kNumGradImages = 2; 243 244 sk_sp<SkImage> fGradImgs[kNumGradImages]; 245 sk_sp<SkImage> fSmallImg; 246 247 using INHERITED = GM; 248 }; 249 250 DEF_GM(return new RectangleTexture;) 251 } // namespace skiagm 252 #endif 253