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