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