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 GM {
23 public:
RectangleTexture()24     RectangleTexture() {
25         this->setBGColor(0xFFFFFFFF);
26     }
27 
28 protected:
onShortName()29     SkString onShortName() override {
30         return SkString("rectangle_texture");
31     }
32 
onISize()33     SkISize onISize() override { return SkISize::Make(1200, 500); }
34 
fillPixels(int width,int height,void * pixels)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 
createRectangleTextureImg(GrContext * context,GrSurfaceOrigin origin,int width,int height,const uint32_t * pixels)55     sk_sp<SkImage> createRectangleTextureImg(GrContext* context, GrSurfaceOrigin origin, int width,
56                                              int height, const uint32_t* pixels) {
57         if (!context) {
58             return nullptr;
59         }
60         if (context->abandoned()) {
61             return nullptr;
62         }
63         GrGpu* gpu = context->contextPriv().getGpu();
64         if (!gpu) {
65             return nullptr;
66         }
67         const GrGLContext* glCtx = gpu->glContextForTesting();
68         if (!glCtx) {
69             return nullptr;
70         }
71 
72         if (!(kGL_GrGLStandard == glCtx->standard() && glCtx->version() >= GR_GL_VER(3, 1)) &&
73             !(glCtx->hasExtension("GL_ARB_texture_rectangle") ||
74               glCtx->hasExtension("GL_ANGLE_texture_rectangle"))) {
75             return nullptr;
76         }
77 
78         // We will always create the GL texture as GL_RGBA, however the pixels uploaded may be
79         // be RGBA or BGRA, depending on how SkPMColor was compiled.
80         GrGLenum format;
81         if (kSkia8888_GrPixelConfig == kBGRA_8888_GrPixelConfig) {
82             format = GR_GL_BGRA;
83         } else {
84             SkASSERT(kSkia8888_GrPixelConfig == kRGBA_8888_GrPixelConfig);
85             format = GR_GL_RGBA;
86         }
87 
88         const GrGLInterface* gl = glCtx->interface();
89         // Useful for debugging whether errors result from use of RECTANGLE
90         // static constexpr GrGLenum kTarget = GR_GL_TEXTURE_2D;
91         static constexpr GrGLenum kTarget = GR_GL_TEXTURE_RECTANGLE;
92         GrGLuint id = 0;
93         GR_GL_CALL(gl, GenTextures(1, &id));
94         GR_GL_CALL(gl, BindTexture(kTarget, id));
95         GR_GL_CALL(gl, TexParameteri(kTarget, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST));
96         GR_GL_CALL(gl, TexParameteri(kTarget, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST));
97         GR_GL_CALL(gl, TexParameteri(kTarget, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE));
98         GR_GL_CALL(gl, TexParameteri(kTarget, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_EDGE));
99         std::unique_ptr<uint32_t[]> tempPixels;
100         if (origin == kBottomLeft_GrSurfaceOrigin) {
101             tempPixels.reset(new uint32_t[width * height]);
102             for (int y = 0; y < height; ++y) {
103                 std::copy_n(pixels + width * (height - y - 1), width, tempPixels.get() + width * y);
104             }
105             pixels = tempPixels.get();
106         }
107         GR_GL_CALL(gl, TexImage2D(kTarget, 0, GR_GL_RGBA, width, height, 0, format,
108                                   GR_GL_UNSIGNED_BYTE, pixels));
109 
110         context->resetContext();
111         GrGLTextureInfo info;
112         info.fID = id;
113         info.fTarget = kTarget;
114         info.fFormat = GR_GL_RGBA8;
115 
116         GrBackendTexture rectangleTex(width, height, GrMipMapped::kNo, info);
117 
118         if (sk_sp<SkImage> image = SkImage::MakeFromAdoptedTexture(context, rectangleTex, origin,
119                                                                    kRGBA_8888_SkColorType)) {
120             return image;
121         }
122         GR_GL_CALL(gl, DeleteTextures(1, &id));
123         return nullptr;
124     }
125 
onDraw(SkCanvas * canvas)126     void onDraw(SkCanvas* canvas) override {
127         GrContext *context = canvas->getGrContext();
128         if (!context) {
129             skiagm::GM::DrawGpuOnlyMessage(canvas);
130             return;
131         }
132 
133         constexpr int kWidth = 50;
134         constexpr int kHeight = 50;
135         constexpr SkScalar kPad = 5.f;
136 
137         SkPMColor pixels[kWidth * kHeight];
138         this->fillPixels(kWidth, kHeight, pixels);
139 
140         sk_sp<SkImage> rectImgs[] = {
141                 this->createRectangleTextureImg(context, kTopLeft_GrSurfaceOrigin, kWidth, kHeight,
142                                                 pixels),
143                 this->createRectangleTextureImg(context, kBottomLeft_GrSurfaceOrigin, kWidth,
144                                                 kHeight, pixels),
145         };
146         SkASSERT(SkToBool(rectImgs[0]) == SkToBool(rectImgs[1]));
147         if (!rectImgs[0]) {
148             SkPaint paint;
149             SkFont font;
150             canvas->drawString("Could not create rectangle texture image.", 10, 100, font, paint);
151             return;
152         }
153 
154         constexpr SkFilterQuality kQualities[] = {
155                 kNone_SkFilterQuality,
156                 kLow_SkFilterQuality,
157                 kMedium_SkFilterQuality,
158                 kHigh_SkFilterQuality,
159         };
160 
161         constexpr SkScalar kScales[] = {1.0f, 1.2f, 0.75f};
162 
163         canvas->translate(kPad, kPad);
164         for (size_t i = 0; i < SK_ARRAY_COUNT(rectImgs); ++i) {
165             for (auto s : kScales) {
166                 canvas->save();
167                 canvas->scale(s, s);
168                 for (auto q : kQualities) {
169                     // drawImage
170                     SkPaint plainPaint;
171                     plainPaint.setFilterQuality(q);
172                     canvas->drawImage(rectImgs[i], 0, 0, &plainPaint);
173                     canvas->translate(kWidth + kPad, 0);
174 
175                     // clamp/clamp shader
176                     SkPaint clampPaint;
177                     clampPaint.setFilterQuality(q);
178                     clampPaint.setShader(rectImgs[i]->makeShader());
179                     canvas->drawRect(SkRect::MakeWH(1.5f * kWidth, 1.5f * kHeight), clampPaint);
180                     canvas->translate(kWidth * 1.5f + kPad, 0);
181 
182                     // repeat/mirror shader
183                     SkPaint repeatPaint;
184                     repeatPaint.setFilterQuality(q);
185                     repeatPaint.setShader(rectImgs[i]->makeShader(SkShader::kRepeat_TileMode,
186                                                                   SkShader::kMirror_TileMode));
187                     canvas->drawRect(SkRect::MakeWH(1.5f * kWidth, 1.5f * kHeight), repeatPaint);
188                     canvas->translate(1.5f * kWidth + kPad, 0);
189 
190                     // drawImageRect with kStrict
191                     auto srcRect = SkRect::MakeXYWH(.25f * rectImgs[i]->width(),
192                                                     .25f * rectImgs[i]->height(),
193                                                     .50f * rectImgs[i]->width(),
194                                                     .50f * rectImgs[i]->height());
195                     auto dstRect = SkRect::MakeXYWH(0, 0,
196                                                     .50f * rectImgs[i]->width(),
197                                                     .50f * rectImgs[i]->height());
198                     canvas->drawImageRect(rectImgs[i], srcRect, dstRect, &plainPaint,
199                                           SkCanvas::kStrict_SrcRectConstraint);
200                     canvas->translate(kWidth * .5f + kPad, 0);
201                 }
202                 canvas->restore();
203                 canvas->translate(0, kPad + 1.5f * kHeight * s);
204             }
205         }
206     }
207 
208 private:
209     typedef GM INHERITED;
210 };
211 
212 DEF_GM(return new RectangleTexture;)
213 }
214