Move all non-AA fill rect ops off of GrLegacyMeshDrawOp.
[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                      SkPMColor* ctable, int* ctableCount) override {
128         SkASSERT(fBM.width() == info.width());
129         SkASSERT(fBM.height() == info.height());
130
131         if (info.colorType() == kIndex_8_SkColorType) {
132             if (SkColorTable* ct = fBM.getColorTable()) {
133                 if (ctable) {
134                     memcpy(ctable, ct->readColors(), ct->count() * sizeof(SkPMColor));
135                 }
136                 if (ctableCount) {
137                     *ctableCount = ct->count();
138                 }
139
140                 for (int y = 0; y < info.height(); ++y) {
141                     memcpy(pixels, fBM.getAddr8(0, y), fBM.width());
142                     pixels = (char*)pixels + rowBytes;
143                 }
144                 return true;
145             } else {
146                 return false;
147             }
148         } else {
149             return fBM.readPixels(info, pixels, rowBytes, 0, 0);
150         }
151     }
152 private:
153     SkBitmap fBM;
154 };
155 static std::unique_ptr<SkImageGenerator> make_ras_generator(GrContext*, sk_sp<SkPicture> pic) {
156     SkBitmap bm;
157     bm.allocN32Pixels(100, 100);
158     SkCanvas canvas(bm);
159     canvas.clear(0);
160     canvas.translate(-100, -100);
161     canvas.drawPicture(pic);
162     return skstd::make_unique<RasterGenerator>(bm);
163 }
164
165 // so we can create a color-table
166 static int find_closest(SkPMColor c, const SkPMColor table[], int count) {
167     const int cr = SkGetPackedR32(c);
168     const int cg = SkGetPackedG32(c);
169     const int cb = SkGetPackedB32(c);
170
171     int minDist = 999999999;
172     int index = 0;
173     for (int i = 0; i < count; ++i) {
174         int dr = SkAbs32((int)SkGetPackedR32(table[i]) - cr);
175         int dg = SkAbs32((int)SkGetPackedG32(table[i]) - cg);
176         int db = SkAbs32((int)SkGetPackedB32(table[i]) - cb);
177         int dist = dr + dg + db;
178         if (dist < minDist) {
179             minDist = dist;
180             index = i;
181         }
182     }
183     return index;
184 }
185
186 static std::unique_ptr<SkImageGenerator> make_ctable_generator(GrContext*, sk_sp<SkPicture> pic) {
187     SkBitmap bm;
188     bm.allocN32Pixels(100, 100);
189     SkCanvas canvas(bm);
190     canvas.clear(0);
191     canvas.translate(-100, -100);
192     canvas.drawPicture(pic);
193
194     const SkPMColor colors[] = {
195         SkPreMultiplyColor(SK_ColorRED),
196         SkPreMultiplyColor(0),
197         SkPreMultiplyColor(SK_ColorBLUE),
198     };
199     const int count = SK_ARRAY_COUNT(colors);
200     SkImageInfo info = SkImageInfo::Make(100, 100, kIndex_8_SkColorType, kPremul_SkAlphaType);
201
202     SkBitmap bm2;
203     bm2.allocPixels(info, SkColorTable::Make(colors, count));
204     for (int y = 0; y < info.height(); ++y) {
205         for (int x = 0; x < info.width(); ++x) {
206             *bm2.getAddr8(x, y) = find_closest(*bm.getAddr32(x, y), colors, count);
207         }
208     }
209     return skstd::make_unique<RasterGenerator>(bm2);
210 }
211
212 class EmptyGenerator : public SkImageGenerator {
213 public:
214     EmptyGenerator(const SkImageInfo& info) : SkImageGenerator(info) {}
215 };
216
217 #if SK_SUPPORT_GPU
218 class TextureGenerator : public SkImageGenerator {
219 public:
220     TextureGenerator(GrContext* ctx, const SkImageInfo& info, sk_sp<SkPicture> pic)
221         : SkImageGenerator(info)
222         , fCtx(SkRef(ctx)) {
223
224         sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info));
225         if (surface) {
226             surface->getCanvas()->clear(0);
227             surface->getCanvas()->translate(-100, -100);
228             surface->getCanvas()->drawPicture(pic);
229             sk_sp<SkImage> image(surface->makeImageSnapshot());
230             fProxy = as_IB(image)->asTextureProxyRef();
231         }
232     }
233 protected:
234     sk_sp<GrTextureProxy> onGenerateTexture(GrContext* ctx, const SkImageInfo& info,
235                                             const SkIPoint& origin) override {
236         SkASSERT(ctx);
237         SkASSERT(ctx == fCtx.get());
238
239         if (!fProxy) {
240             return nullptr;
241         }
242
243         if (origin.fX == 0 && origin.fY == 0 &&
244             info.width() == fProxy->width() && info.height() == fProxy->height()) {
245             return fProxy;
246         }
247
248         // need to copy the subset into a new texture
249         GrSurfaceDesc desc = fProxy->desc();
250         desc.fWidth = info.width();
251         desc.fHeight = info.height();
252
253         sk_sp<GrSurfaceContext> dstContext(fCtx->contextPriv().makeDeferredSurfaceContext(
254                                                                             desc,
255                                                                             SkBackingFit::kExact,
256                                                                             SkBudgeted::kNo));
257         if (!dstContext) {
258             return nullptr;
259         }
260
261         if (!dstContext->copy(
262                             fProxy.get(),
263                             SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height()),
264                             SkIPoint::Make(0, 0))) {
265             return nullptr;
266         }
267
268         return dstContext->asTextureProxyRef();
269     }
270
271 private:
272     sk_sp<GrContext>      fCtx;
273     sk_sp<GrTextureProxy> fProxy;
274 };
275
276 static std::unique_ptr<SkImageGenerator> make_tex_generator(GrContext* ctx, sk_sp<SkPicture> pic) {
277     const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
278
279     if (!ctx) {
280         return skstd::make_unique<EmptyGenerator>(info);
281     }
282     return skstd::make_unique<TextureGenerator>(ctx, info, pic);
283 }
284 #endif
285
286 class ImageCacheratorGM : public skiagm::GM {
287     SkString                         fName;
288     std::unique_ptr<SkImageGenerator> (*fFactory)(GrContext*, sk_sp<SkPicture>);
289     sk_sp<SkPicture>                 fPicture;
290     sk_sp<SkImage>                   fImage;
291     sk_sp<SkImage>                   fImageSubset;
292
293 public:
294     ImageCacheratorGM(const char suffix[],
295                       std::unique_ptr<SkImageGenerator> (*factory)(GrContext*, sk_sp<SkPicture>))
296         : fFactory(factory)
297     {
298         fName.printf("image-cacherator-from-%s", suffix);
299     }
300
301 protected:
302     SkString onShortName() override {
303         return fName;
304     }
305
306     SkISize onISize() override {
307         return SkISize::Make(960, 450);
308     }
309
310     void onOnceBeforeDraw() override {
311         const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
312         SkPictureRecorder recorder;
313         draw_something(recorder.beginRecording(bounds), bounds);
314         fPicture = recorder.finishRecordingAsPicture();
315     }
316
317     void makeCaches(GrContext* ctx) {
318         auto gen = fFactory(ctx, fPicture);
319         fImage = SkImage::MakeFromGenerator(std::move(gen));
320
321         const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
322
323         gen = fFactory(ctx, fPicture);
324         fImageSubset = SkImage::MakeFromGenerator(std::move(gen), &subset);
325
326         SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
327         SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
328     }
329
330     static void draw_as_bitmap(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
331         SkBitmap bitmap;
332         as_IB(image)->getROPixels(&bitmap, canvas->imageInfo().colorSpace());
333         canvas->drawBitmap(bitmap, x, y);
334     }
335
336     static void draw_as_tex(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
337 #if SK_SUPPORT_GPU
338         sk_sp<SkColorSpace> texColorSpace;
339         sk_sp<GrTextureProxy> proxy(
340             as_IB(image)->asTextureProxyRef(canvas->getGrContext(), GrSamplerParams::ClampBilerp(),
341                                             canvas->imageInfo().colorSpace(), &texColorSpace,
342                                             nullptr));
343         if (!proxy) {
344             // show placeholder if we have no texture
345             SkPaint paint;
346             paint.setStyle(SkPaint::kStroke_Style);
347             SkRect r = SkRect::MakeXYWH(x, y, SkIntToScalar(image->width()),
348                                         SkIntToScalar(image->width()));
349             canvas->drawRect(r, paint);
350             canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
351             canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
352             return;
353         }
354
355         // No API to draw a GrTexture directly, so we cheat and create a private image subclass
356         sk_sp<SkImage> texImage(new SkImage_Gpu(canvas->getGrContext(), image->uniqueID(),
357                                                 kPremul_SkAlphaType, std::move(proxy),
358                                                 std::move(texColorSpace), SkBudgeted::kNo));
359         canvas->drawImage(texImage.get(), x, y);
360 #endif
361     }
362
363     void drawSet(SkCanvas* canvas) const {
364         SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
365         canvas->drawPicture(fPicture, &matrix, nullptr);
366
367         // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This
368         // way we also can force the generateTexture call.
369
370         draw_as_tex(canvas, fImage.get(), 310, 0);
371         draw_as_tex(canvas, fImageSubset.get(), 310+101, 0);
372
373         draw_as_bitmap(canvas, fImage.get(), 150, 0);
374         draw_as_bitmap(canvas, fImageSubset.get(), 150+101, 0);
375     }
376
377     void onDraw(SkCanvas* canvas) override {
378         this->makeCaches(canvas->getGrContext());
379
380         canvas->translate(20, 20);
381
382         this->drawSet(canvas);
383
384         canvas->save();
385         canvas->translate(0, 130);
386         canvas->scale(0.25f, 0.25f);
387         this->drawSet(canvas);
388         canvas->restore();
389
390         canvas->save();
391         canvas->translate(0, 200);
392         canvas->scale(2, 2);
393         this->drawSet(canvas);
394         canvas->restore();
395     }
396
397 private:
398     typedef skiagm::GM INHERITED;
399 };
400 DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator); )
401 DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator); )
402 DEF_GM( return new ImageCacheratorGM("ctable", make_ctable_generator); )
403 #if SK_SUPPORT_GPU
404     DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator); )
405 #endif