Add fixes & test for isConfigTexturable and isConfigRenderable
[platform/upstream/libSkiaSharp.git] / gm / image_pict.cpp
1 /*
2  * Copyright 2015 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 #include "gm.h"
9 #include "SkCanvas.h"
10 #include "SkImage.h"
11 #include "SkImageGenerator.h"
12 #include "SkImage_Base.h"
13 #include "SkMakeUnique.h"
14 #include "SkPictureRecorder.h"
15 #include "SkSurface.h"
16
17 #if SK_SUPPORT_GPU
18 #include "GrContext.h"
19 #include "GrContextPriv.h"
20 #include "GrSurfaceContext.h"
21 #include "GrSurfaceProxy.h"
22 #include "GrTexture.h"
23 #include "GrTextureProxy.h"
24 #include "../src/image/SkImage_Gpu.h"
25 #endif
26
27 static void draw_something(SkCanvas* canvas, const SkRect& bounds) {
28     SkPaint paint;
29     paint.setAntiAlias(true);
30     paint.setColor(SK_ColorRED);
31     paint.setStyle(SkPaint::kStroke_Style);
32     paint.setStrokeWidth(10);
33     canvas->drawRect(bounds, paint);
34     paint.setStyle(SkPaint::kFill_Style);
35     paint.setColor(SK_ColorBLUE);
36     canvas->drawOval(bounds, paint);
37 }
38
39 /*
40  *  Exercise drawing pictures inside an image, showing that the image version is pixelated
41  *  (correctly) when it is inside an image.
42  */
43 class ImagePictGM : public skiagm::GM {
44     sk_sp<SkPicture> fPicture;
45     sk_sp<SkImage>   fImage0;
46     sk_sp<SkImage>   fImage1;
47 public:
48     ImagePictGM() {}
49
50 protected:
51     SkString onShortName() override {
52         return SkString("image-picture");
53     }
54
55     SkISize onISize() override {
56         return SkISize::Make(850, 450);
57     }
58
59     void onOnceBeforeDraw() override {
60         const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
61         SkPictureRecorder recorder;
62         draw_something(recorder.beginRecording(bounds), bounds);
63         fPicture = recorder.finishRecordingAsPicture();
64
65         // extract enough just for the oval.
66         const SkISize size = SkISize::Make(100, 100);
67         auto srgbColorSpace = SkColorSpace::MakeSRGB();
68
69         SkMatrix matrix;
70         matrix.setTranslate(-100, -100);
71         fImage0 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
72                                            SkImage::BitDepth::kU8, srgbColorSpace);
73         matrix.postTranslate(-50, -50);
74         matrix.postRotate(45);
75         matrix.postTranslate(50, 50);
76         fImage1 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
77                                            SkImage::BitDepth::kU8, srgbColorSpace);
78     }
79
80     void drawSet(SkCanvas* canvas) const {
81         SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
82         canvas->drawPicture(fPicture, &matrix, nullptr);
83         canvas->drawImage(fImage0.get(), 150, 0);
84         canvas->drawImage(fImage1.get(), 300, 0);
85     }
86
87     void onDraw(SkCanvas* canvas) override {
88         canvas->translate(20, 20);
89
90         this->drawSet(canvas);
91
92         canvas->save();
93         canvas->translate(0, 130);
94         canvas->scale(0.25f, 0.25f);
95         this->drawSet(canvas);
96         canvas->restore();
97
98         canvas->save();
99         canvas->translate(0, 200);
100         canvas->scale(2, 2);
101         this->drawSet(canvas);
102         canvas->restore();
103     }
104
105 private:
106     typedef skiagm::GM INHERITED;
107 };
108 DEF_GM( return new ImagePictGM; )
109
110 ///////////////////////////////////////////////////////////////////////////////////////////////////
111
112 static std::unique_ptr<SkImageGenerator> make_pic_generator(GrContext*, sk_sp<SkPicture> pic) {
113     SkMatrix matrix;
114     matrix.setTranslate(-100, -100);
115     return SkImageGenerator::MakeFromPicture({ 100, 100 }, std::move(pic), &matrix, nullptr,
116                                             SkImage::BitDepth::kU8,
117                                             SkColorSpace::MakeSRGB());
118 }
119
120 class RasterGenerator : public SkImageGenerator {
121 public:
122     RasterGenerator(const SkBitmap& bm) : SkImageGenerator(bm.info()), fBM(bm)
123     {}
124
125 protected:
126     bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
127                      const Options&) override {
128         SkASSERT(fBM.width() == info.width());
129         SkASSERT(fBM.height() == info.height());
130         return fBM.readPixels(info, pixels, rowBytes, 0, 0);
131     }
132 private:
133     SkBitmap fBM;
134 };
135 static std::unique_ptr<SkImageGenerator> make_ras_generator(GrContext*, sk_sp<SkPicture> pic) {
136     SkBitmap bm;
137     bm.allocN32Pixels(100, 100);
138     SkCanvas canvas(bm);
139     canvas.clear(0);
140     canvas.translate(-100, -100);
141     canvas.drawPicture(pic);
142     return skstd::make_unique<RasterGenerator>(bm);
143 }
144
145 class EmptyGenerator : public SkImageGenerator {
146 public:
147     EmptyGenerator(const SkImageInfo& info) : SkImageGenerator(info) {}
148 };
149
150 #if SK_SUPPORT_GPU
151 class TextureGenerator : public SkImageGenerator {
152 public:
153     TextureGenerator(GrContext* ctx, const SkImageInfo& info, sk_sp<SkPicture> pic)
154         : SkImageGenerator(info)
155         , fCtx(SkRef(ctx)) {
156
157         sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info));
158         if (surface) {
159             surface->getCanvas()->clear(0);
160             surface->getCanvas()->translate(-100, -100);
161             surface->getCanvas()->drawPicture(pic);
162             sk_sp<SkImage> image(surface->makeImageSnapshot());
163             fProxy = as_IB(image)->asTextureProxyRef();
164         }
165     }
166 protected:
167     sk_sp<GrTextureProxy> onGenerateTexture(GrContext* ctx, const SkImageInfo& info,
168                                             const SkIPoint& origin) override {
169         SkASSERT(ctx);
170         SkASSERT(ctx == fCtx.get());
171
172         if (!fProxy) {
173             return nullptr;
174         }
175
176         if (origin.fX == 0 && origin.fY == 0 &&
177             info.width() == fProxy->width() && info.height() == fProxy->height()) {
178             return fProxy;
179         }
180
181         // need to copy the subset into a new texture
182         GrSurfaceDesc desc;
183         desc.fConfig = fProxy->config();
184         desc.fWidth = info.width();
185         desc.fHeight = info.height();
186         desc.fOrigin = fProxy->origin();
187
188         sk_sp<GrSurfaceContext> dstContext(fCtx->contextPriv().makeDeferredSurfaceContext(
189                                                                             desc,
190                                                                             SkBackingFit::kExact,
191                                                                             SkBudgeted::kNo));
192         if (!dstContext) {
193             return nullptr;
194         }
195
196         if (!dstContext->copy(
197                             fProxy.get(),
198                             SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height()),
199                             SkIPoint::Make(0, 0))) {
200             return nullptr;
201         }
202
203         return dstContext->asTextureProxyRef();
204     }
205
206 private:
207     sk_sp<GrContext>      fCtx;
208     sk_sp<GrTextureProxy> fProxy;
209 };
210
211 static std::unique_ptr<SkImageGenerator> make_tex_generator(GrContext* ctx, sk_sp<SkPicture> pic) {
212     const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
213
214     if (!ctx) {
215         return skstd::make_unique<EmptyGenerator>(info);
216     }
217     return skstd::make_unique<TextureGenerator>(ctx, info, pic);
218 }
219 #endif
220
221 class ImageCacheratorGM : public skiagm::GM {
222     SkString                         fName;
223     std::unique_ptr<SkImageGenerator> (*fFactory)(GrContext*, sk_sp<SkPicture>);
224     sk_sp<SkPicture>                 fPicture;
225     sk_sp<SkImage>                   fImage;
226     sk_sp<SkImage>                   fImageSubset;
227
228 public:
229     ImageCacheratorGM(const char suffix[],
230                       std::unique_ptr<SkImageGenerator> (*factory)(GrContext*, sk_sp<SkPicture>))
231         : fFactory(factory)
232     {
233         fName.printf("image-cacherator-from-%s", suffix);
234     }
235
236 protected:
237     SkString onShortName() override {
238         return fName;
239     }
240
241     SkISize onISize() override {
242         return SkISize::Make(960, 450);
243     }
244
245     void onOnceBeforeDraw() override {
246         const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
247         SkPictureRecorder recorder;
248         draw_something(recorder.beginRecording(bounds), bounds);
249         fPicture = recorder.finishRecordingAsPicture();
250     }
251
252     void makeCaches(GrContext* ctx) {
253         auto gen = fFactory(ctx, fPicture);
254         fImage = SkImage::MakeFromGenerator(std::move(gen));
255
256         const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
257
258         gen = fFactory(ctx, fPicture);
259         fImageSubset = SkImage::MakeFromGenerator(std::move(gen), &subset);
260
261         SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
262         SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
263     }
264
265     static void draw_as_bitmap(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
266         SkBitmap bitmap;
267         as_IB(image)->getROPixels(&bitmap, canvas->imageInfo().colorSpace());
268         canvas->drawBitmap(bitmap, x, y);
269     }
270
271     static void draw_as_tex(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
272 #if SK_SUPPORT_GPU
273         sk_sp<SkColorSpace> texColorSpace;
274         sk_sp<GrTextureProxy> proxy(
275             as_IB(image)->asTextureProxyRef(canvas->getGrContext(), GrSamplerParams::ClampBilerp(),
276                                             canvas->imageInfo().colorSpace(), &texColorSpace,
277                                             nullptr));
278         if (!proxy) {
279             // show placeholder if we have no texture
280             SkPaint paint;
281             paint.setStyle(SkPaint::kStroke_Style);
282             SkRect r = SkRect::MakeXYWH(x, y, SkIntToScalar(image->width()),
283                                         SkIntToScalar(image->width()));
284             canvas->drawRect(r, paint);
285             canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
286             canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
287             return;
288         }
289
290         // No API to draw a GrTexture directly, so we cheat and create a private image subclass
291         sk_sp<SkImage> texImage(new SkImage_Gpu(canvas->getGrContext(), image->uniqueID(),
292                                                 kPremul_SkAlphaType, std::move(proxy),
293                                                 std::move(texColorSpace), SkBudgeted::kNo));
294         canvas->drawImage(texImage.get(), x, y);
295 #endif
296     }
297
298     void drawSet(SkCanvas* canvas) const {
299         SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
300         canvas->drawPicture(fPicture, &matrix, nullptr);
301
302         // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This
303         // way we also can force the generateTexture call.
304
305         draw_as_tex(canvas, fImage.get(), 310, 0);
306         draw_as_tex(canvas, fImageSubset.get(), 310+101, 0);
307
308         draw_as_bitmap(canvas, fImage.get(), 150, 0);
309         draw_as_bitmap(canvas, fImageSubset.get(), 150+101, 0);
310     }
311
312     void onDraw(SkCanvas* canvas) override {
313         this->makeCaches(canvas->getGrContext());
314
315         canvas->translate(20, 20);
316
317         this->drawSet(canvas);
318
319         canvas->save();
320         canvas->translate(0, 130);
321         canvas->scale(0.25f, 0.25f);
322         this->drawSet(canvas);
323         canvas->restore();
324
325         canvas->save();
326         canvas->translate(0, 200);
327         canvas->scale(2, 2);
328         this->drawSet(canvas);
329         canvas->restore();
330     }
331
332 private:
333     typedef skiagm::GM INHERITED;
334 };
335 DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator); )
336 DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator); )
337 #if SK_SUPPORT_GPU
338     DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator); )
339 #endif