• 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/GrDirectContext.h"
29 #include "include/gpu/GrRecordingContext.h"
30 #include "include/gpu/GrTypes.h"
31 #include "include/private/GrTypesPriv.h"
32 #include "src/gpu/GrRecordingContextPriv.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::Translate(-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     using INHERITED = skiagm::GM;
124 };
DEF_GM(return new ImagePictGM;)125 DEF_GM( return new ImagePictGM; )
126 
127 ///////////////////////////////////////////////////////////////////////////////////////////////////
128 
129 static std::unique_ptr<SkImageGenerator> make_pic_generator(GrDirectContext*,
130                                                             sk_sp<SkPicture> pic) {
131     SkMatrix matrix;
132     matrix.setTranslate(-100, -100);
133     return SkImageGenerator::MakeFromPicture({ 100, 100 }, std::move(pic), &matrix, nullptr,
134                                             SkImage::BitDepth::kU8,
135                                             SkColorSpace::MakeSRGB());
136 }
137 
138 class RasterGenerator : public SkImageGenerator {
139 public:
RasterGenerator(const SkBitmap & bm)140     RasterGenerator(const SkBitmap& bm) : SkImageGenerator(bm.info()), fBM(bm)
141     {}
142 
143 protected:
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options &)144     bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
145                      const Options&) override {
146         SkASSERT(fBM.width() == info.width());
147         SkASSERT(fBM.height() == info.height());
148         return fBM.readPixels(info, pixels, rowBytes, 0, 0);
149     }
150 private:
151     SkBitmap fBM;
152 };
make_ras_generator(GrDirectContext *,sk_sp<SkPicture> pic)153 static std::unique_ptr<SkImageGenerator> make_ras_generator(GrDirectContext*,
154                                                             sk_sp<SkPicture> pic) {
155     SkBitmap bm;
156     bm.allocN32Pixels(100, 100);
157     SkCanvas canvas(bm);
158     canvas.clear(0);
159     canvas.translate(-100, -100);
160     canvas.drawPicture(pic);
161     return std::make_unique<RasterGenerator>(bm);
162 }
163 
164 class TextureGenerator : public SkImageGenerator {
165 public:
TextureGenerator(GrRecordingContext * rContext,const SkImageInfo & info,sk_sp<SkPicture> pic)166     TextureGenerator(GrRecordingContext* rContext, const SkImageInfo& info, sk_sp<SkPicture> pic)
167             : SkImageGenerator(info)
168             , fRContext(SkRef(rContext)) {
169 
170         sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(rContext, SkBudgeted::kYes, info, 0,
171                                                              kTopLeft_GrSurfaceOrigin, nullptr));
172         if (surface) {
173             surface->getCanvas()->clear(0);
174             surface->getCanvas()->translate(-100, -100);
175             surface->getCanvas()->drawPicture(pic);
176             sk_sp<SkImage> image(surface->makeImageSnapshot());
177             std::tie(fView, std::ignore) = as_IB(image)->asView(rContext, GrMipmapped::kNo);
178         }
179     }
180 protected:
onGenerateTexture(GrRecordingContext * rContext,const SkImageInfo & info,const SkIPoint & origin,GrMipmapped mipMapped,GrImageTexGenPolicy policy)181     GrSurfaceProxyView onGenerateTexture(GrRecordingContext* rContext,
182                                          const SkImageInfo& info,
183                                          const SkIPoint& origin,
184                                          GrMipmapped mipMapped,
185                                          GrImageTexGenPolicy policy) override {
186         SkASSERT(rContext);
187         SkASSERT(rContext->priv().matches(fRContext.get()));
188 
189         if (!fView) {
190             return {};
191         }
192 
193         if (origin.fX == 0 && origin.fY == 0 && info.dimensions() == fView.proxy()->dimensions() &&
194             policy == GrImageTexGenPolicy::kDraw) {
195             return fView;
196         }
197         auto budgeted = policy == GrImageTexGenPolicy::kNew_Uncached_Unbudgeted ? SkBudgeted::kNo
198                                                                                 : SkBudgeted::kYes;
199         return GrSurfaceProxyView::Copy(
200                 fRContext.get(), fView, mipMapped,
201                 SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height()),
202                 SkBackingFit::kExact, budgeted);
203     }
204 
205 private:
206     sk_sp<GrRecordingContext> fRContext;
207     GrSurfaceProxyView        fView;
208 };
209 
make_tex_generator(GrDirectContext * dContext,sk_sp<SkPicture> pic)210 static std::unique_ptr<SkImageGenerator> make_tex_generator(GrDirectContext* dContext,
211                                                             sk_sp<SkPicture> pic) {
212     if (!dContext) {
213         return nullptr;
214     }
215 
216     const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
217 
218     return std::make_unique<TextureGenerator>(dContext, info, pic);
219 }
220 
221 class ImageCacheratorGM : public skiagm::GM {
222     typedef std::unique_ptr<SkImageGenerator> (*FactoryFunc)(GrDirectContext*, sk_sp<SkPicture>);
223 
224     SkString         fName;
225     FactoryFunc      fFactory;
226     sk_sp<SkPicture> fPicture;
227     sk_sp<SkImage>   fImage;
228     sk_sp<SkImage>   fImageSubset;
229 
230 public:
ImageCacheratorGM(const char suffix[],FactoryFunc factory)231     ImageCacheratorGM(const char suffix[], FactoryFunc factory) : fFactory(factory) {
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(GrDirectContext * dContext)251     bool makeCaches(GrDirectContext* dContext) {
252         {
253             auto gen = fFactory(dContext, fPicture);
254             if (!gen) {
255                 return false;
256             }
257             fImage = SkImage::MakeFromGenerator(std::move(gen));
258             if (!fImage) {
259                 return false;
260             }
261             SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
262         }
263 
264         {
265             const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
266 
267             // We re-create the generator here on the off chance that making a subset from
268             // 'fImage' might perturb its state.
269             auto gen = fFactory(dContext, fPicture);
270             if (!gen) {
271                 return false;
272             }
273             fImageSubset = SkImage::MakeFromGenerator(std::move(gen))->makeSubset(subset, dContext);
274             if (!fImageSubset) {
275                 return false;
276             }
277             SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
278         }
279 
280         return true;
281     }
282 
draw_placeholder(SkCanvas * canvas,SkScalar x,SkScalar y,int w,int h)283     static void draw_placeholder(SkCanvas* canvas, SkScalar x, SkScalar y, int w, int h) {
284         SkPaint paint;
285         paint.setStyle(SkPaint::kStroke_Style);
286         SkRect r = SkRect::MakeXYWH(x, y, SkIntToScalar(w), SkIntToScalar(h));
287         canvas->drawRect(r, paint);
288         canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
289         canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
290     }
291 
draw_as_bitmap(GrDirectContext * dContext,SkCanvas * canvas,SkImage * image,SkScalar x,SkScalar y)292     static void draw_as_bitmap(GrDirectContext* dContext, SkCanvas* canvas, SkImage* image,
293                                SkScalar x, SkScalar y) {
294         SkBitmap bitmap;
295         if (as_IB(image)->getROPixels(dContext, &bitmap)) {
296             canvas->drawImage(bitmap.asImage(), x, y);
297         } else {
298             draw_placeholder(canvas, x, y, image->width(), image->height());
299         }
300     }
301 
draw_as_tex(SkCanvas * canvas,SkImage * image,SkScalar x,SkScalar y)302     static void draw_as_tex(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
303         // The gpu-backed images are drawn in this manner bc the generator backed images
304         // aren't considered texture-backed
305         auto [view, ct] = as_IB(image)->asView(canvas->recordingContext(), GrMipmapped::kNo);
306         if (!view) {
307             // show placeholder if we have no texture
308             draw_placeholder(canvas, x, y, image->width(), image->height());
309             return;
310         }
311         SkColorInfo colorInfo(GrColorTypeToSkColorType(ct),
312                               image->alphaType(),
313                               image->refColorSpace());
314         // No API to draw a GrTexture directly, so we cheat and create a private image subclass
315         sk_sp<SkImage> texImage(new SkImage_Gpu(sk_ref_sp(canvas->recordingContext()),
316                                                 image->uniqueID(),
317                                                 std::move(view),
318                                                 std::move(colorInfo)));
319         canvas->drawImage(texImage.get(), x, y);
320     }
321 
drawRow(GrDirectContext * dContext,SkCanvas * canvas,float scale) const322     void drawRow(GrDirectContext* dContext, SkCanvas* canvas, float scale) const {
323         canvas->scale(scale, scale);
324 
325         SkMatrix matrix = SkMatrix::Translate(-100, -100);
326         canvas->drawPicture(fPicture, &matrix, nullptr);
327 
328         // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This
329         // way we also can force the generateTexture call.
330 
331         draw_as_tex(canvas, fImage.get(), 150, 0);
332         draw_as_tex(canvas, fImageSubset.get(), 150+101, 0);
333 
334         draw_as_bitmap(dContext, canvas, fImage.get(), 310, 0);
335         draw_as_bitmap(dContext, canvas, fImageSubset.get(), 310+101, 0);
336     }
337 
onDraw(SkCanvas * canvas,SkString * errorMsg)338     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
339         auto dContext = GrAsDirectContext(canvas->recordingContext());
340         if (!this->makeCaches(dContext)) {
341             errorMsg->printf("Could not create cached images");
342             return DrawResult::kSkip;
343         }
344 
345         canvas->save();
346             canvas->translate(20, 20);
347             this->drawRow(dContext, canvas, 1.0);
348         canvas->restore();
349 
350         canvas->save();
351             canvas->translate(20, 150);
352             this->drawRow(dContext, canvas, 0.25f);
353         canvas->restore();
354 
355         canvas->save();
356             canvas->translate(20, 220);
357             this->drawRow(dContext, canvas, 2.0f);
358         canvas->restore();
359 
360         return DrawResult::kOk;
361     }
362 
363 private:
364     using INHERITED = skiagm::GM;
365 };
366 
367 DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator); )
368 DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator); )
369 DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator); )
370