• 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/gpu/ganesh/GrTypesPriv.h"
32 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
33 #include "src/gpu/ganesh/GrSamplerState.h"
34 #include "src/gpu/ganesh/GrTextureProxy.h"
35 #include "src/gpu/ganesh/SurfaceContext.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(SkCanvas*,
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(SkCanvas *,sk_sp<SkPicture> pic)153 static std::unique_ptr<SkImageGenerator> make_ras_generator(SkCanvas*,
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(SkCanvas * canvas,const SkImageInfo & info,sk_sp<SkPicture> pic)166     TextureGenerator(SkCanvas* canvas, const SkImageInfo& info, sk_sp<SkPicture> pic)
167             : SkImageGenerator(info) {
168 
169         fRContext = sk_ref_sp(canvas->recordingContext());
170 
171         sk_sp<SkSurface> surface;
172 
173         if (fRContext) {
174             surface = SkSurface::MakeRenderTarget(fRContext.get(), skgpu::Budgeted::kYes, info,
175                                                   0, kTopLeft_GrSurfaceOrigin, nullptr);
176         }
177 #if defined(SK_GRAPHITE)
178         if (skgpu::graphite::Recorder* recorder = canvas->recorder()) {
179             surface = SkSurface::MakeGraphite(recorder, info);
180         }
181 #endif
182 
183         if (surface) {
184             surface->getCanvas()->clear(0);
185             surface->getCanvas()->translate(-100, -100);
186             surface->getCanvas()->drawPicture(pic);
187             fImage = surface->makeImageSnapshot();
188         }
189     }
190 protected:
onGenerateTexture(GrRecordingContext * rContext,const SkImageInfo & info,GrMipmapped mipmapped,GrImageTexGenPolicy policy)191     GrSurfaceProxyView onGenerateTexture(GrRecordingContext* rContext,
192                                          const SkImageInfo& info,
193                                          GrMipmapped mipmapped,
194                                          GrImageTexGenPolicy policy) override {
195         SkASSERT(rContext);
196         SkASSERT(rContext->priv().matches(fRContext.get()));
197 
198         GrSurfaceProxyView view;
199 
200         std::tie(view, std::ignore) = as_IB(fImage)->asView(rContext, GrMipmapped::kNo);
201         if (!view) {
202             return {};
203         }
204 
205         SkASSERT_RELEASE(info.dimensions() == view.proxy()->dimensions());
206 
207         if (policy == GrImageTexGenPolicy::kDraw) {
208             return view;
209         }
210         auto budgeted = policy == GrImageTexGenPolicy::kNew_Uncached_Unbudgeted
211                                 ? skgpu::Budgeted::kNo
212                                 : skgpu::Budgeted::kYes;
213         return GrSurfaceProxyView::Copy(
214                 fRContext.get(),
215                 view,
216                 mipmapped,
217                 SkIRect::MakeWH(info.width(), info.height()),
218                 SkBackingFit::kExact,
219                 budgeted,
220                 /*label=*/"SurfaceProxyView_GenerateTexture");
221     }
222 
223 #if defined(SK_GRAPHITE)
onMakeTextureImage(skgpu::graphite::Recorder *,const SkImageInfo &,skgpu::Mipmapped)224     sk_sp<SkImage> onMakeTextureImage(skgpu::graphite::Recorder*,
225                                       const SkImageInfo&,
226                                       skgpu::Mipmapped) override {
227         return fImage;
228     }
229 #endif
230 
231 private:
232     sk_sp<GrRecordingContext> fRContext;
233     sk_sp<SkImage>            fImage;
234 };
235 
make_tex_generator(SkCanvas * canvas,sk_sp<SkPicture> pic)236 static std::unique_ptr<SkImageGenerator> make_tex_generator(SkCanvas* canvas,
237                                                             sk_sp<SkPicture> pic) {
238     auto dContext = GrAsDirectContext(canvas->recordingContext());
239     if (!dContext && !canvas->recorder()) {
240         return nullptr;
241     }
242 
243     const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
244 
245     return std::make_unique<TextureGenerator>(canvas, info, pic);
246 }
247 
248 class ImageCacheratorGM : public skiagm::GM {
249     typedef std::unique_ptr<SkImageGenerator> (*FactoryFunc)(SkCanvas*, sk_sp<SkPicture>);
250 
251     SkString         fName;
252     FactoryFunc      fFactory;
253     sk_sp<SkPicture> fPicture;
254     sk_sp<SkImage>   fImage;
255     sk_sp<SkImage>   fImageSubset;
256 
257 public:
ImageCacheratorGM(const char suffix[],FactoryFunc factory)258     ImageCacheratorGM(const char suffix[], FactoryFunc factory) : fFactory(factory) {
259         fName.printf("image-cacherator-from-%s", suffix);
260     }
261 
262 protected:
onShortName()263     SkString onShortName() override {
264         return fName;
265     }
266 
onISize()267     SkISize onISize() override {
268         return SkISize::Make(960, 450);
269     }
270 
onOnceBeforeDraw()271     void onOnceBeforeDraw() override {
272         const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
273         SkPictureRecorder recorder;
274         draw_something(recorder.beginRecording(bounds), bounds);
275         fPicture = recorder.finishRecordingAsPicture();
276     }
277 
makeCaches(SkCanvas * canvas)278     bool makeCaches(SkCanvas* canvas) {
279         auto dContext = GrAsDirectContext(canvas->recordingContext());
280 
281         {
282             auto gen = fFactory(canvas, fPicture);
283             if (!gen) {
284                 return false;
285             }
286             fImage = SkImage::MakeFromGenerator(std::move(gen));
287             if (!fImage) {
288                 return false;
289             }
290             SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
291         }
292 
293         {
294             const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
295 
296             // We re-create the generator here on the off chance that making a subset from
297             // 'fImage' might perturb its state.
298             auto gen = fFactory(canvas, fPicture);
299             if (!gen) {
300                 return false;
301             }
302 
303             if (dContext) {
304                 fImageSubset = SkImage::MakeFromGenerator(std::move(gen))->makeSubset(subset,
305                                                                                       dContext);
306             } else {
307 #if defined(SK_GRAPHITE)
308                 auto recorder = canvas->recorder();
309                 fImageSubset = SkImage::MakeFromGenerator(std::move(gen))->makeSubset(subset,
310                                                                                       recorder);
311 #endif
312             }
313             if (!fImageSubset) {
314                 return false;
315             }
316             SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
317         }
318 
319         return true;
320     }
321 
draw_placeholder(SkCanvas * canvas,SkScalar x,SkScalar y,int w,int h)322     static void draw_placeholder(SkCanvas* canvas, SkScalar x, SkScalar y, int w, int h) {
323         SkPaint paint;
324         paint.setStyle(SkPaint::kStroke_Style);
325         SkRect r = SkRect::MakeXYWH(x, y, SkIntToScalar(w), SkIntToScalar(h));
326         canvas->drawRect(r, paint);
327         canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
328         canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
329     }
330 
draw_as_bitmap(GrDirectContext * dContext,SkCanvas * canvas,SkImage * image,SkScalar x,SkScalar y)331     static void draw_as_bitmap(GrDirectContext* dContext, SkCanvas* canvas, SkImage* image,
332                                SkScalar x, SkScalar y) {
333         SkBitmap bitmap;
334         if (as_IB(image)->getROPixels(dContext, &bitmap)) {
335             canvas->drawImage(bitmap.asImage(), x, y);
336         } else {
337             draw_placeholder(canvas, x, y, image->width(), image->height());
338         }
339     }
340 
draw_as_tex(SkCanvas * canvas,SkImage * image,SkScalar x,SkScalar y)341     static void draw_as_tex(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
342         if (as_IB(image)->isGaneshBacked()) {
343             // The gpu-backed images are drawn in this manner bc the generator backed images
344             // aren't considered texture-backed
345             auto [view, ct] = as_IB(image)->asView(canvas->recordingContext(), GrMipmapped::kNo);
346             if (!view) {
347                 // show placeholder if we have no texture
348                 draw_placeholder(canvas, x, y, image->width(), image->height());
349                 return;
350             }
351             SkColorInfo colorInfo(GrColorTypeToSkColorType(ct),
352                                   image->alphaType(),
353                                   image->refColorSpace());
354             // No API to draw a GrTexture directly, so we cheat and create a private image subclass
355             sk_sp<SkImage> texImage(new SkImage_Gpu(sk_ref_sp(canvas->recordingContext()),
356                                                     image->uniqueID(),
357                                                     std::move(view),
358                                                     std::move(colorInfo)));
359             canvas->drawImage(texImage.get(), x, y);
360         } else {
361             canvas->drawImage(image, x, y);
362         }
363     }
364 
drawRow(GrDirectContext * dContext,SkCanvas * canvas,float scale) const365     void drawRow(GrDirectContext* dContext, SkCanvas* canvas, float scale) const {
366         canvas->scale(scale, scale);
367 
368         SkMatrix matrix = SkMatrix::Translate(-100, -100);
369         canvas->drawPicture(fPicture, &matrix, nullptr);
370 
371         // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This
372         // way we also can force the generateTexture call.
373 
374         draw_as_tex(canvas, fImage.get(), 150, 0);
375         draw_as_tex(canvas, fImageSubset.get(), 150+101, 0);
376 
377         draw_as_bitmap(dContext, canvas, fImage.get(), 310, 0);
378         draw_as_bitmap(dContext, canvas, fImageSubset.get(), 310+101, 0);
379     }
380 
onDraw(SkCanvas * canvas,SkString * errorMsg)381     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
382         auto dContext = GrAsDirectContext(canvas->recordingContext());
383         if (!this->makeCaches(canvas)) {
384             errorMsg->printf("Could not create cached images");
385             return DrawResult::kSkip;
386         }
387 
388         canvas->save();
389             canvas->translate(20, 20);
390             this->drawRow(dContext, canvas, 1.0);
391         canvas->restore();
392 
393         canvas->save();
394             canvas->translate(20, 150);
395             this->drawRow(dContext, canvas, 0.25f);
396         canvas->restore();
397 
398         canvas->save();
399             canvas->translate(20, 220);
400             this->drawRow(dContext, canvas, 2.0f);
401         canvas->restore();
402 
403         return DrawResult::kOk;
404     }
405 
406 private:
407     using INHERITED = skiagm::GM;
408 };
409 
410 DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator); )
411 DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator); )
412 DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator); )
413