Home | History | Annotate | Download | only in gm
      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 GPU backend.
      9 
     10 #include "gm.h"
     11 
     12 #include "GrBackendSurface.h"
     13 #include "GrContext.h"
     14 #include "GrContextPriv.h"
     15 #include "GrGpu.h"
     16 #include "gl/GrGLContext.h"
     17 #include "SkBitmap.h"
     18 #include "SkGradientShader.h"
     19 #include "SkImage.h"
     20 
     21 namespace skiagm {
     22 class RectangleTexture : public GpuGM {
     23 public:
     24     RectangleTexture() {
     25         this->setBGColor(0xFFFFFFFF);
     26     }
     27 
     28 protected:
     29     SkString onShortName() override {
     30         return SkString("rectangle_texture");
     31     }
     32 
     33     SkISize onISize() override { return SkISize::Make(1200, 500); }
     34 
     35     void fillPixels(int width, int height, void *pixels) {
     36         SkBitmap bmp;
     37         bmp.setInfo(SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType), width * 4);
     38         bmp.setPixels(pixels);
     39         SkPaint paint;
     40         SkCanvas canvas(bmp);
     41         SkPoint pts[] = { {0, 0}, {0, SkIntToScalar(height)} };
     42         SkColor colors0[] = { 0xFF1060B0 , 0xFF102030 };
     43         paint.setShader(SkGradientShader::MakeLinear(pts, colors0, nullptr, 2,
     44                                                      SkShader::kClamp_TileMode));
     45         canvas.drawPaint(paint);
     46 
     47         SkColor colors1[] = {0xFFA07010, 0xFFA02080};
     48         paint.setAntiAlias(true);
     49         paint.setShader(SkGradientShader::MakeLinear(pts, colors1, nullptr, 2,
     50                                                      SkShader::kClamp_TileMode));
     51         canvas.drawCircle(SkIntToScalar(width) / 2, SkIntToScalar(height) / 2,
     52                           SkIntToScalar(width + height) / 5, paint);
     53     }
     54 
     55     sk_sp<SkImage> createRectangleTextureImg(GrContext* context, GrSurfaceOrigin origin, int width,
     56                                              int height, const uint32_t* pixels) {
     57         GrGpu* gpu = context->priv().getGpu();
     58         if (!gpu) {
     59             return nullptr;
     60         }
     61         const GrGLContext* glCtx = gpu->glContextForTesting();
     62         if (!glCtx) {
     63             return nullptr;
     64         }
     65 
     66         if (!(kGL_GrGLStandard == glCtx->standard() && glCtx->version() >= GR_GL_VER(3, 1)) &&
     67             !(glCtx->hasExtension("GL_ARB_texture_rectangle") ||
     68               glCtx->hasExtension("GL_ANGLE_texture_rectangle"))) {
     69             return nullptr;
     70         }
     71 
     72         // We will always create the GL texture as GL_RGBA, however the pixels uploaded may be
     73         // be RGBA or BGRA, depending on how SkPMColor was compiled.
     74         GrGLenum format;
     75         if (kSkia8888_GrPixelConfig == kBGRA_8888_GrPixelConfig) {
     76             format = GR_GL_BGRA;
     77         } else {
     78             SkASSERT(kSkia8888_GrPixelConfig == kRGBA_8888_GrPixelConfig);
     79             format = GR_GL_RGBA;
     80         }
     81 
     82         const GrGLInterface* gl = glCtx->interface();
     83         // Useful for debugging whether errors result from use of RECTANGLE
     84         // static constexpr GrGLenum kTarget = GR_GL_TEXTURE_2D;
     85         static constexpr GrGLenum kTarget = GR_GL_TEXTURE_RECTANGLE;
     86         GrGLuint id = 0;
     87         GR_GL_CALL(gl, GenTextures(1, &id));
     88         GR_GL_CALL(gl, BindTexture(kTarget, id));
     89         GR_GL_CALL(gl, TexParameteri(kTarget, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST));
     90         GR_GL_CALL(gl, TexParameteri(kTarget, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST));
     91         GR_GL_CALL(gl, TexParameteri(kTarget, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE));
     92         GR_GL_CALL(gl, TexParameteri(kTarget, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_EDGE));
     93         std::unique_ptr<uint32_t[]> tempPixels;
     94         if (origin == kBottomLeft_GrSurfaceOrigin) {
     95             tempPixels.reset(new uint32_t[width * height]);
     96             for (int y = 0; y < height; ++y) {
     97                 std::copy_n(pixels + width * (height - y - 1), width, tempPixels.get() + width * y);
     98             }
     99             pixels = tempPixels.get();
    100         }
    101         GR_GL_CALL(gl, TexImage2D(kTarget, 0, GR_GL_RGBA, width, height, 0, format,
    102                                   GR_GL_UNSIGNED_BYTE, pixels));
    103 
    104         context->resetContext();
    105         GrGLTextureInfo info;
    106         info.fID = id;
    107         info.fTarget = kTarget;
    108         info.fFormat = GR_GL_RGBA8;
    109 
    110         GrBackendTexture rectangleTex(width, height, GrMipMapped::kNo, info);
    111 
    112         if (sk_sp<SkImage> image = SkImage::MakeFromAdoptedTexture(context, rectangleTex, origin,
    113                                                                    kRGBA_8888_SkColorType)) {
    114             return image;
    115         }
    116         GR_GL_CALL(gl, DeleteTextures(1, &id));
    117         return nullptr;
    118     }
    119 
    120     DrawResult onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas,
    121                       SkString* errorMsg) override {
    122         constexpr int kWidth = 50;
    123         constexpr int kHeight = 50;
    124         constexpr SkScalar kPad = 5.f;
    125 
    126         SkPMColor pixels[kWidth * kHeight];
    127         this->fillPixels(kWidth, kHeight, pixels);
    128 
    129         sk_sp<SkImage> rectImgs[] = {
    130                 this->createRectangleTextureImg(context, kTopLeft_GrSurfaceOrigin, kWidth, kHeight,
    131                                                 pixels),
    132                 this->createRectangleTextureImg(context, kBottomLeft_GrSurfaceOrigin, kWidth,
    133                                                 kHeight, pixels),
    134         };
    135         SkASSERT(SkToBool(rectImgs[0]) == SkToBool(rectImgs[1]));
    136         if (!rectImgs[0]) {
    137             *errorMsg = "Could not create rectangle texture image.";
    138             return DrawResult::kFail;
    139         }
    140 
    141         constexpr SkFilterQuality kQualities[] = {
    142                 kNone_SkFilterQuality,
    143                 kLow_SkFilterQuality,
    144                 kMedium_SkFilterQuality,
    145                 kHigh_SkFilterQuality,
    146         };
    147 
    148         constexpr SkScalar kScales[] = {1.0f, 1.2f, 0.75f};
    149 
    150         canvas->translate(kPad, kPad);
    151         for (size_t i = 0; i < SK_ARRAY_COUNT(rectImgs); ++i) {
    152             for (auto s : kScales) {
    153                 canvas->save();
    154                 canvas->scale(s, s);
    155                 for (auto q : kQualities) {
    156                     // drawImage
    157                     SkPaint plainPaint;
    158                     plainPaint.setFilterQuality(q);
    159                     canvas->drawImage(rectImgs[i], 0, 0, &plainPaint);
    160                     canvas->translate(kWidth + kPad, 0);
    161 
    162                     // clamp/clamp shader
    163                     SkPaint clampPaint;
    164                     clampPaint.setFilterQuality(q);
    165                     clampPaint.setShader(rectImgs[i]->makeShader());
    166                     canvas->drawRect(SkRect::MakeWH(1.5f * kWidth, 1.5f * kHeight), clampPaint);
    167                     canvas->translate(kWidth * 1.5f + kPad, 0);
    168 
    169                     // repeat/mirror shader
    170                     SkPaint repeatPaint;
    171                     repeatPaint.setFilterQuality(q);
    172                     repeatPaint.setShader(rectImgs[i]->makeShader(SkShader::kRepeat_TileMode,
    173                                                                   SkShader::kMirror_TileMode));
    174                     canvas->drawRect(SkRect::MakeWH(1.5f * kWidth, 1.5f * kHeight), repeatPaint);
    175                     canvas->translate(1.5f * kWidth + kPad, 0);
    176 
    177                     // drawImageRect with kStrict
    178                     auto srcRect = SkRect::MakeXYWH(.25f * rectImgs[i]->width(),
    179                                                     .25f * rectImgs[i]->height(),
    180                                                     .50f * rectImgs[i]->width(),
    181                                                     .50f * rectImgs[i]->height());
    182                     auto dstRect = SkRect::MakeXYWH(0, 0,
    183                                                     .50f * rectImgs[i]->width(),
    184                                                     .50f * rectImgs[i]->height());
    185                     canvas->drawImageRect(rectImgs[i], srcRect, dstRect, &plainPaint,
    186                                           SkCanvas::kStrict_SrcRectConstraint);
    187                     canvas->translate(kWidth * .5f + kPad, 0);
    188                 }
    189                 canvas->restore();
    190                 canvas->translate(0, kPad + 1.5f * kHeight * s);
    191             }
    192         }
    193         return DrawResult::kOk;
    194     }
    195 
    196 private:
    197     typedef GM INHERITED;
    198 };
    199 
    200 DEF_GM(return new RectangleTexture;)
    201 }
    202