xref: /aosp_15_r20/external/skia/gm/image_pict.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2015 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageGenerator.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPictureRecorder.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrTypes.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrExternalTextureGenerator.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkSurfaceGanesh.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTextureGenerator.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSamplerState.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTextureProxy.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SurfaceContext.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/image/GrImageUtils.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/image/SkImage_Ganesh.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/image/SkImageGeneratorPriv.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/image/SkImage_Base.h"
43*c8dee2aaSAndroid Build Coastguard Worker 
44*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
45*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
48*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/graphite/Surface.h"
49*c8dee2aaSAndroid Build Coastguard Worker #endif
50*c8dee2aaSAndroid Build Coastguard Worker 
51*c8dee2aaSAndroid Build Coastguard Worker class GrRecordingContext;
52*c8dee2aaSAndroid Build Coastguard Worker 
draw_something(SkCanvas * canvas,const SkRect & bounds)53*c8dee2aaSAndroid Build Coastguard Worker static void draw_something(SkCanvas* canvas, const SkRect& bounds) {
54*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
55*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
56*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(SK_ColorRED);
57*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kStroke_Style);
58*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeWidth(10);
59*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(bounds, paint);
60*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kFill_Style);
61*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(SK_ColorBLUE);
62*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawOval(bounds, paint);
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker 
65*c8dee2aaSAndroid Build Coastguard Worker /*
66*c8dee2aaSAndroid Build Coastguard Worker  *  Exercise drawing pictures inside an image, showing that the image version is pixelated
67*c8dee2aaSAndroid Build Coastguard Worker  *  (correctly) when it is inside an image.
68*c8dee2aaSAndroid Build Coastguard Worker  */
69*c8dee2aaSAndroid Build Coastguard Worker class ImagePictGM : public skiagm::GM {
70*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkPicture> fPicture;
71*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage>   fImage0;
72*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage>   fImage1;
73*c8dee2aaSAndroid Build Coastguard Worker public:
ImagePictGM()74*c8dee2aaSAndroid Build Coastguard Worker     ImagePictGM() {}
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const77*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("image-picture"); }
78*c8dee2aaSAndroid Build Coastguard Worker 
getISize()79*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return SkISize::Make(850, 450); }
80*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()81*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
82*c8dee2aaSAndroid Build Coastguard Worker         const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
83*c8dee2aaSAndroid Build Coastguard Worker         SkPictureRecorder recorder;
84*c8dee2aaSAndroid Build Coastguard Worker         draw_something(recorder.beginRecording(bounds), bounds);
85*c8dee2aaSAndroid Build Coastguard Worker         fPicture = recorder.finishRecordingAsPicture();
86*c8dee2aaSAndroid Build Coastguard Worker 
87*c8dee2aaSAndroid Build Coastguard Worker         // extract enough just for the oval.
88*c8dee2aaSAndroid Build Coastguard Worker         const SkISize size = SkISize::Make(100, 100);
89*c8dee2aaSAndroid Build Coastguard Worker         auto srgbColorSpace = SkColorSpace::MakeSRGB();
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrix;
92*c8dee2aaSAndroid Build Coastguard Worker         matrix.setTranslate(-100, -100);
93*c8dee2aaSAndroid Build Coastguard Worker         fImage0 = SkImages::DeferredFromPicture(
94*c8dee2aaSAndroid Build Coastguard Worker                 fPicture, size, &matrix, nullptr, SkImages::BitDepth::kU8, srgbColorSpace);
95*c8dee2aaSAndroid Build Coastguard Worker         matrix.postTranslate(-50, -50);
96*c8dee2aaSAndroid Build Coastguard Worker         matrix.postRotate(45);
97*c8dee2aaSAndroid Build Coastguard Worker         matrix.postTranslate(50, 50);
98*c8dee2aaSAndroid Build Coastguard Worker         fImage1 = SkImages::DeferredFromPicture(
99*c8dee2aaSAndroid Build Coastguard Worker                 fPicture, size, &matrix, nullptr, SkImages::BitDepth::kU8, srgbColorSpace);
100*c8dee2aaSAndroid Build Coastguard Worker     }
101*c8dee2aaSAndroid Build Coastguard Worker 
drawSet(SkCanvas * canvas) const102*c8dee2aaSAndroid Build Coastguard Worker     void drawSet(SkCanvas* canvas) const {
103*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrix = SkMatrix::Translate(-100, -100);
104*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPicture(fPicture, &matrix, nullptr);
105*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawImage(fImage0.get(), 150, 0);
106*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawImage(fImage1.get(), 300, 0);
107*c8dee2aaSAndroid Build Coastguard Worker     }
108*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas)109*c8dee2aaSAndroid Build Coastguard Worker     void onDraw(SkCanvas* canvas) override {
110*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(20, 20);
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker         this->drawSet(canvas);
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker         canvas->save();
115*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(0, 130);
116*c8dee2aaSAndroid Build Coastguard Worker         canvas->scale(0.25f, 0.25f);
117*c8dee2aaSAndroid Build Coastguard Worker         this->drawSet(canvas);
118*c8dee2aaSAndroid Build Coastguard Worker         canvas->restore();
119*c8dee2aaSAndroid Build Coastguard Worker 
120*c8dee2aaSAndroid Build Coastguard Worker         canvas->save();
121*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(0, 200);
122*c8dee2aaSAndroid Build Coastguard Worker         canvas->scale(2, 2);
123*c8dee2aaSAndroid Build Coastguard Worker         this->drawSet(canvas);
124*c8dee2aaSAndroid Build Coastguard Worker         canvas->restore();
125*c8dee2aaSAndroid Build Coastguard Worker     }
126*c8dee2aaSAndroid Build Coastguard Worker 
127*c8dee2aaSAndroid Build Coastguard Worker private:
128*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = skiagm::GM;
129*c8dee2aaSAndroid Build Coastguard Worker };
DEF_GM(return new ImagePictGM;)130*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new ImagePictGM; )
131*c8dee2aaSAndroid Build Coastguard Worker 
132*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<SkImageGenerator> make_pic_generator(SkCanvas*,
135*c8dee2aaSAndroid Build Coastguard Worker                                                             sk_sp<SkPicture> pic) {
136*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix matrix;
137*c8dee2aaSAndroid Build Coastguard Worker     matrix.setTranslate(-100, -100);
138*c8dee2aaSAndroid Build Coastguard Worker     return SkImageGenerators::MakeFromPicture({100, 100},
139*c8dee2aaSAndroid Build Coastguard Worker                                               std::move(pic),
140*c8dee2aaSAndroid Build Coastguard Worker                                               &matrix,
141*c8dee2aaSAndroid Build Coastguard Worker                                               nullptr,
142*c8dee2aaSAndroid Build Coastguard Worker                                               SkImages::BitDepth::kU8,
143*c8dee2aaSAndroid Build Coastguard Worker                                               SkColorSpace::MakeSRGB());
144*c8dee2aaSAndroid Build Coastguard Worker }
145*c8dee2aaSAndroid Build Coastguard Worker 
146*c8dee2aaSAndroid Build Coastguard Worker class RasterGenerator : public SkImageGenerator {
147*c8dee2aaSAndroid Build Coastguard Worker public:
RasterGenerator(const SkBitmap & bm)148*c8dee2aaSAndroid Build Coastguard Worker     RasterGenerator(const SkBitmap& bm) : SkImageGenerator(bm.info()), fBM(bm)
149*c8dee2aaSAndroid Build Coastguard Worker     {}
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker protected:
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options &)152*c8dee2aaSAndroid Build Coastguard Worker     bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
153*c8dee2aaSAndroid Build Coastguard Worker                      const Options&) override {
154*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fBM.width() == info.width());
155*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fBM.height() == info.height());
156*c8dee2aaSAndroid Build Coastguard Worker         return fBM.readPixels(info, pixels, rowBytes, 0, 0);
157*c8dee2aaSAndroid Build Coastguard Worker     }
158*c8dee2aaSAndroid Build Coastguard Worker private:
159*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap fBM;
160*c8dee2aaSAndroid Build Coastguard Worker };
make_ras_generator(SkCanvas *,sk_sp<SkPicture> pic)161*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<SkImageGenerator> make_ras_generator(SkCanvas*,
162*c8dee2aaSAndroid Build Coastguard Worker                                                             sk_sp<SkPicture> pic) {
163*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap bm;
164*c8dee2aaSAndroid Build Coastguard Worker     bm.allocN32Pixels(100, 100);
165*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas canvas(bm);
166*c8dee2aaSAndroid Build Coastguard Worker     canvas.clear(0);
167*c8dee2aaSAndroid Build Coastguard Worker     canvas.translate(-100, -100);
168*c8dee2aaSAndroid Build Coastguard Worker     canvas.drawPicture(pic);
169*c8dee2aaSAndroid Build Coastguard Worker     return std::make_unique<RasterGenerator>(bm);
170*c8dee2aaSAndroid Build Coastguard Worker }
171*c8dee2aaSAndroid Build Coastguard Worker 
172*c8dee2aaSAndroid Build Coastguard Worker class TextureGenerator : public GrTextureGenerator {
173*c8dee2aaSAndroid Build Coastguard Worker public:
TextureGenerator(SkCanvas * canvas,const SkImageInfo & info,sk_sp<SkPicture> pic)174*c8dee2aaSAndroid Build Coastguard Worker     TextureGenerator(SkCanvas* canvas, const SkImageInfo& info, sk_sp<SkPicture> pic)
175*c8dee2aaSAndroid Build Coastguard Worker             : GrTextureGenerator(info) {
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker         fRContext = sk_ref_sp(canvas->recordingContext());
178*c8dee2aaSAndroid Build Coastguard Worker 
179*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkSurface> surface;
180*c8dee2aaSAndroid Build Coastguard Worker 
181*c8dee2aaSAndroid Build Coastguard Worker         if (fRContext) {
182*c8dee2aaSAndroid Build Coastguard Worker             surface = SkSurfaces::RenderTarget(fRContext.get(),
183*c8dee2aaSAndroid Build Coastguard Worker                                                skgpu::Budgeted::kYes,
184*c8dee2aaSAndroid Build Coastguard Worker                                                info,
185*c8dee2aaSAndroid Build Coastguard Worker                                                0,
186*c8dee2aaSAndroid Build Coastguard Worker                                                kTopLeft_GrSurfaceOrigin,
187*c8dee2aaSAndroid Build Coastguard Worker                                                nullptr);
188*c8dee2aaSAndroid Build Coastguard Worker         }
189*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
190*c8dee2aaSAndroid Build Coastguard Worker         if (skgpu::graphite::Recorder* recorder = canvas->recorder()) {
191*c8dee2aaSAndroid Build Coastguard Worker             surface = SkSurfaces::RenderTarget(recorder, info);
192*c8dee2aaSAndroid Build Coastguard Worker         }
193*c8dee2aaSAndroid Build Coastguard Worker #endif
194*c8dee2aaSAndroid Build Coastguard Worker 
195*c8dee2aaSAndroid Build Coastguard Worker         if (surface) {
196*c8dee2aaSAndroid Build Coastguard Worker             surface->getCanvas()->clear(0);
197*c8dee2aaSAndroid Build Coastguard Worker             surface->getCanvas()->translate(-100, -100);
198*c8dee2aaSAndroid Build Coastguard Worker             surface->getCanvas()->drawPicture(pic);
199*c8dee2aaSAndroid Build Coastguard Worker             fImage = surface->makeImageSnapshot();
200*c8dee2aaSAndroid Build Coastguard Worker         }
201*c8dee2aaSAndroid Build Coastguard Worker     }
202*c8dee2aaSAndroid Build Coastguard Worker protected:
onGenerateTexture(GrRecordingContext * rContext,const SkImageInfo & info,skgpu::Mipmapped mipmapped,GrImageTexGenPolicy policy)203*c8dee2aaSAndroid Build Coastguard Worker     GrSurfaceProxyView onGenerateTexture(GrRecordingContext* rContext,
204*c8dee2aaSAndroid Build Coastguard Worker                                          const SkImageInfo& info,
205*c8dee2aaSAndroid Build Coastguard Worker                                          skgpu::Mipmapped mipmapped,
206*c8dee2aaSAndroid Build Coastguard Worker                                          GrImageTexGenPolicy policy) override {
207*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(rContext);
208*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(rContext->priv().matches(fRContext.get()));
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker         auto [view, _] = skgpu::ganesh::AsView(rContext, fImage, skgpu::Mipmapped::kNo);
211*c8dee2aaSAndroid Build Coastguard Worker         if (!view) {
212*c8dee2aaSAndroid Build Coastguard Worker             return {};
213*c8dee2aaSAndroid Build Coastguard Worker         }
214*c8dee2aaSAndroid Build Coastguard Worker 
215*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT_RELEASE(info.dimensions() == view.proxy()->dimensions());
216*c8dee2aaSAndroid Build Coastguard Worker 
217*c8dee2aaSAndroid Build Coastguard Worker         if (policy == GrImageTexGenPolicy::kDraw) {
218*c8dee2aaSAndroid Build Coastguard Worker             return view;
219*c8dee2aaSAndroid Build Coastguard Worker         }
220*c8dee2aaSAndroid Build Coastguard Worker         auto budgeted = policy == GrImageTexGenPolicy::kNew_Uncached_Unbudgeted
221*c8dee2aaSAndroid Build Coastguard Worker                                 ? skgpu::Budgeted::kNo
222*c8dee2aaSAndroid Build Coastguard Worker                                 : skgpu::Budgeted::kYes;
223*c8dee2aaSAndroid Build Coastguard Worker         return GrSurfaceProxyView::Copy(
224*c8dee2aaSAndroid Build Coastguard Worker                 fRContext.get(),
225*c8dee2aaSAndroid Build Coastguard Worker                 view,
226*c8dee2aaSAndroid Build Coastguard Worker                 mipmapped,
227*c8dee2aaSAndroid Build Coastguard Worker                 SkIRect::MakeWH(info.width(), info.height()),
228*c8dee2aaSAndroid Build Coastguard Worker                 SkBackingFit::kExact,
229*c8dee2aaSAndroid Build Coastguard Worker                 budgeted,
230*c8dee2aaSAndroid Build Coastguard Worker                 /*label=*/"SurfaceProxyView_GenerateTexture");
231*c8dee2aaSAndroid Build Coastguard Worker     }
232*c8dee2aaSAndroid Build Coastguard Worker 
233*c8dee2aaSAndroid Build Coastguard Worker private:
234*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<GrRecordingContext> fRContext;
235*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage>            fImage;
236*c8dee2aaSAndroid Build Coastguard Worker };
237*c8dee2aaSAndroid Build Coastguard Worker 
make_tex_generator(SkCanvas * canvas,sk_sp<SkPicture> pic)238*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<SkImageGenerator> make_tex_generator(SkCanvas* canvas,
239*c8dee2aaSAndroid Build Coastguard Worker                                                             sk_sp<SkPicture> pic) {
240*c8dee2aaSAndroid Build Coastguard Worker     auto dContext = GrAsDirectContext(canvas->recordingContext());
241*c8dee2aaSAndroid Build Coastguard Worker     if (!dContext && !canvas->recorder()) {
242*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
243*c8dee2aaSAndroid Build Coastguard Worker     }
244*c8dee2aaSAndroid Build Coastguard Worker 
245*c8dee2aaSAndroid Build Coastguard Worker     const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
246*c8dee2aaSAndroid Build Coastguard Worker 
247*c8dee2aaSAndroid Build Coastguard Worker     return std::make_unique<TextureGenerator>(canvas, info, pic);
248*c8dee2aaSAndroid Build Coastguard Worker }
249*c8dee2aaSAndroid Build Coastguard Worker 
250*c8dee2aaSAndroid Build Coastguard Worker class ImageCacheratorGM : public skiagm::GM {
251*c8dee2aaSAndroid Build Coastguard Worker     typedef std::unique_ptr<SkImageGenerator> (*FactoryFunc)(SkCanvas*, sk_sp<SkPicture>);
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker     SkString         fName;
254*c8dee2aaSAndroid Build Coastguard Worker     FactoryFunc      fFactory;
255*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkPicture> fPicture;
256*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage>   fImage;
257*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage>   fImageSubset;
258*c8dee2aaSAndroid Build Coastguard Worker     bool             fUseTexture;
259*c8dee2aaSAndroid Build Coastguard Worker 
260*c8dee2aaSAndroid Build Coastguard Worker public:
ImageCacheratorGM(const char suffix[],FactoryFunc factory,bool useTexture)261*c8dee2aaSAndroid Build Coastguard Worker     ImageCacheratorGM(const char suffix[], FactoryFunc factory, bool useTexture) :
262*c8dee2aaSAndroid Build Coastguard Worker                     fFactory(factory), fUseTexture(useTexture) {
263*c8dee2aaSAndroid Build Coastguard Worker         fName.printf("image-cacherator-from-%s", suffix);
264*c8dee2aaSAndroid Build Coastguard Worker     }
265*c8dee2aaSAndroid Build Coastguard Worker 
266*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const267*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return fName; }
268*c8dee2aaSAndroid Build Coastguard Worker 
getISize()269*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return SkISize::Make(960, 450); }
270*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()271*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
272*c8dee2aaSAndroid Build Coastguard Worker         const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
273*c8dee2aaSAndroid Build Coastguard Worker         SkPictureRecorder recorder;
274*c8dee2aaSAndroid Build Coastguard Worker         draw_something(recorder.beginRecording(bounds), bounds);
275*c8dee2aaSAndroid Build Coastguard Worker         fPicture = recorder.finishRecordingAsPicture();
276*c8dee2aaSAndroid Build Coastguard Worker     }
277*c8dee2aaSAndroid Build Coastguard Worker 
makeCaches(SkCanvas * canvas)278*c8dee2aaSAndroid Build Coastguard Worker     bool makeCaches(SkCanvas* canvas) {
279*c8dee2aaSAndroid Build Coastguard Worker         auto dContext = GrAsDirectContext(canvas->recordingContext());
280*c8dee2aaSAndroid Build Coastguard Worker 
281*c8dee2aaSAndroid Build Coastguard Worker         {
282*c8dee2aaSAndroid Build Coastguard Worker             auto gen = fFactory(canvas, fPicture);
283*c8dee2aaSAndroid Build Coastguard Worker             if (!gen) {
284*c8dee2aaSAndroid Build Coastguard Worker                 return false;
285*c8dee2aaSAndroid Build Coastguard Worker             }
286*c8dee2aaSAndroid Build Coastguard Worker             if (fUseTexture) {
287*c8dee2aaSAndroid Build Coastguard Worker                 auto textureGen = std::unique_ptr<GrTextureGenerator>(
288*c8dee2aaSAndroid Build Coastguard Worker                         static_cast<GrTextureGenerator*>(gen.release()));
289*c8dee2aaSAndroid Build Coastguard Worker                 fImage = SkImages::DeferredFromTextureGenerator(std::move(textureGen));
290*c8dee2aaSAndroid Build Coastguard Worker             } else {
291*c8dee2aaSAndroid Build Coastguard Worker                 fImage = SkImages::DeferredFromGenerator(std::move(gen));
292*c8dee2aaSAndroid Build Coastguard Worker             }
293*c8dee2aaSAndroid Build Coastguard Worker             if (!fImage) {
294*c8dee2aaSAndroid Build Coastguard Worker                 return false;
295*c8dee2aaSAndroid Build Coastguard Worker             }
296*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
297*c8dee2aaSAndroid Build Coastguard Worker         }
298*c8dee2aaSAndroid Build Coastguard Worker 
299*c8dee2aaSAndroid Build Coastguard Worker         {
300*c8dee2aaSAndroid Build Coastguard Worker             const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
301*c8dee2aaSAndroid Build Coastguard Worker 
302*c8dee2aaSAndroid Build Coastguard Worker             // We re-create the generator here on the off chance that making a subset from
303*c8dee2aaSAndroid Build Coastguard Worker             // 'fImage' might perturb its state.
304*c8dee2aaSAndroid Build Coastguard Worker             auto gen = fFactory(canvas, fPicture);
305*c8dee2aaSAndroid Build Coastguard Worker             if (!gen) {
306*c8dee2aaSAndroid Build Coastguard Worker                 return false;
307*c8dee2aaSAndroid Build Coastguard Worker             }
308*c8dee2aaSAndroid Build Coastguard Worker 
309*c8dee2aaSAndroid Build Coastguard Worker             if (dContext) {
310*c8dee2aaSAndroid Build Coastguard Worker                  if (fUseTexture) {
311*c8dee2aaSAndroid Build Coastguard Worker                     auto textureGen = std::unique_ptr<GrTextureGenerator>(
312*c8dee2aaSAndroid Build Coastguard Worker                         static_cast<GrTextureGenerator*>(gen.release()));
313*c8dee2aaSAndroid Build Coastguard Worker                     fImageSubset = SkImages::DeferredFromTextureGenerator(std::move(textureGen))
314*c8dee2aaSAndroid Build Coastguard Worker                             ->makeSubset(dContext, subset);
315*c8dee2aaSAndroid Build Coastguard Worker                 } else {
316*c8dee2aaSAndroid Build Coastguard Worker                     fImageSubset = SkImages::DeferredFromGenerator(std::move(gen))
317*c8dee2aaSAndroid Build Coastguard Worker                             ->makeSubset(dContext, subset);
318*c8dee2aaSAndroid Build Coastguard Worker                 }
319*c8dee2aaSAndroid Build Coastguard Worker             } else {
320*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GRAPHITE)
321*c8dee2aaSAndroid Build Coastguard Worker                 auto recorder = canvas->recorder();
322*c8dee2aaSAndroid Build Coastguard Worker                 fImageSubset = SkImages::DeferredFromGenerator(std::move(gen))
323*c8dee2aaSAndroid Build Coastguard Worker                                        ->makeSubset(recorder, subset, {});
324*c8dee2aaSAndroid Build Coastguard Worker #endif
325*c8dee2aaSAndroid Build Coastguard Worker             }
326*c8dee2aaSAndroid Build Coastguard Worker             if (!fImageSubset) {
327*c8dee2aaSAndroid Build Coastguard Worker                 return false;
328*c8dee2aaSAndroid Build Coastguard Worker             }
329*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
330*c8dee2aaSAndroid Build Coastguard Worker         }
331*c8dee2aaSAndroid Build Coastguard Worker 
332*c8dee2aaSAndroid Build Coastguard Worker         return true;
333*c8dee2aaSAndroid Build Coastguard Worker     }
334*c8dee2aaSAndroid Build Coastguard Worker 
draw_placeholder(SkCanvas * canvas,SkScalar x,SkScalar y,int w,int h)335*c8dee2aaSAndroid Build Coastguard Worker     static void draw_placeholder(SkCanvas* canvas, SkScalar x, SkScalar y, int w, int h) {
336*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
337*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kStroke_Style);
338*c8dee2aaSAndroid Build Coastguard Worker         SkRect r = SkRect::MakeXYWH(x, y, SkIntToScalar(w), SkIntToScalar(h));
339*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawRect(r, paint);
340*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
341*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
342*c8dee2aaSAndroid Build Coastguard Worker     }
343*c8dee2aaSAndroid Build Coastguard Worker 
draw_as_bitmap(GrDirectContext * dContext,SkCanvas * canvas,SkImage * image,SkScalar x,SkScalar y)344*c8dee2aaSAndroid Build Coastguard Worker     static void draw_as_bitmap(GrDirectContext* dContext, SkCanvas* canvas, SkImage* image,
345*c8dee2aaSAndroid Build Coastguard Worker                                SkScalar x, SkScalar y) {
346*c8dee2aaSAndroid Build Coastguard Worker         SkBitmap bitmap;
347*c8dee2aaSAndroid Build Coastguard Worker         if (as_IB(image)->getROPixels(dContext, &bitmap)) {
348*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawImage(bitmap.asImage(), x, y);
349*c8dee2aaSAndroid Build Coastguard Worker         } else {
350*c8dee2aaSAndroid Build Coastguard Worker             draw_placeholder(canvas, x, y, image->width(), image->height());
351*c8dee2aaSAndroid Build Coastguard Worker         }
352*c8dee2aaSAndroid Build Coastguard Worker     }
353*c8dee2aaSAndroid Build Coastguard Worker 
draw_as_tex(SkCanvas * canvas,SkImage * image,SkScalar x,SkScalar y)354*c8dee2aaSAndroid Build Coastguard Worker     static void draw_as_tex(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
355*c8dee2aaSAndroid Build Coastguard Worker         if (as_IB(image)->isGaneshBacked()) {
356*c8dee2aaSAndroid Build Coastguard Worker             // The gpu-backed images are drawn in this manner bc the generator backed images
357*c8dee2aaSAndroid Build Coastguard Worker             // aren't considered texture-backed
358*c8dee2aaSAndroid Build Coastguard Worker             auto [view, ct] =
359*c8dee2aaSAndroid Build Coastguard Worker                     skgpu::ganesh::AsView(canvas->recordingContext(), image, skgpu::Mipmapped::kNo);
360*c8dee2aaSAndroid Build Coastguard Worker             if (!view) {
361*c8dee2aaSAndroid Build Coastguard Worker                 // show placeholder if we have no texture
362*c8dee2aaSAndroid Build Coastguard Worker                 draw_placeholder(canvas, x, y, image->width(), image->height());
363*c8dee2aaSAndroid Build Coastguard Worker                 return;
364*c8dee2aaSAndroid Build Coastguard Worker             }
365*c8dee2aaSAndroid Build Coastguard Worker             SkColorInfo colorInfo(GrColorTypeToSkColorType(ct),
366*c8dee2aaSAndroid Build Coastguard Worker                                   image->alphaType(),
367*c8dee2aaSAndroid Build Coastguard Worker                                   image->refColorSpace());
368*c8dee2aaSAndroid Build Coastguard Worker             // No API to draw a GrTexture directly, so we cheat and create a private image subclass
369*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<SkImage> texImage(new SkImage_Ganesh(sk_ref_sp(canvas->recordingContext()),
370*c8dee2aaSAndroid Build Coastguard Worker                                                        image->uniqueID(),
371*c8dee2aaSAndroid Build Coastguard Worker                                                        std::move(view),
372*c8dee2aaSAndroid Build Coastguard Worker                                                        std::move(colorInfo)));
373*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawImage(texImage.get(), x, y);
374*c8dee2aaSAndroid Build Coastguard Worker         } else {
375*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawImage(image, x, y);
376*c8dee2aaSAndroid Build Coastguard Worker         }
377*c8dee2aaSAndroid Build Coastguard Worker     }
378*c8dee2aaSAndroid Build Coastguard Worker 
drawRow(GrDirectContext * dContext,SkCanvas * canvas,float scale) const379*c8dee2aaSAndroid Build Coastguard Worker     void drawRow(GrDirectContext* dContext, SkCanvas* canvas, float scale) const {
380*c8dee2aaSAndroid Build Coastguard Worker         canvas->scale(scale, scale);
381*c8dee2aaSAndroid Build Coastguard Worker 
382*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrix = SkMatrix::Translate(-100, -100);
383*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPicture(fPicture, &matrix, nullptr);
384*c8dee2aaSAndroid Build Coastguard Worker 
385*c8dee2aaSAndroid Build Coastguard Worker         // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This
386*c8dee2aaSAndroid Build Coastguard Worker         // way we also can force the generateTexture call.
387*c8dee2aaSAndroid Build Coastguard Worker 
388*c8dee2aaSAndroid Build Coastguard Worker         draw_as_tex(canvas, fImage.get(), 150, 0);
389*c8dee2aaSAndroid Build Coastguard Worker         draw_as_tex(canvas, fImageSubset.get(), 150+101, 0);
390*c8dee2aaSAndroid Build Coastguard Worker 
391*c8dee2aaSAndroid Build Coastguard Worker         draw_as_bitmap(dContext, canvas, fImage.get(), 310, 0);
392*c8dee2aaSAndroid Build Coastguard Worker         draw_as_bitmap(dContext, canvas, fImageSubset.get(), 310+101, 0);
393*c8dee2aaSAndroid Build Coastguard Worker     }
394*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * errorMsg)395*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
396*c8dee2aaSAndroid Build Coastguard Worker         auto dContext = GrAsDirectContext(canvas->recordingContext());
397*c8dee2aaSAndroid Build Coastguard Worker         if (!this->makeCaches(canvas)) {
398*c8dee2aaSAndroid Build Coastguard Worker             errorMsg->printf("Could not create cached images");
399*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
400*c8dee2aaSAndroid Build Coastguard Worker         }
401*c8dee2aaSAndroid Build Coastguard Worker 
402*c8dee2aaSAndroid Build Coastguard Worker         canvas->save();
403*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(20, 20);
404*c8dee2aaSAndroid Build Coastguard Worker             this->drawRow(dContext, canvas, 1.0);
405*c8dee2aaSAndroid Build Coastguard Worker         canvas->restore();
406*c8dee2aaSAndroid Build Coastguard Worker 
407*c8dee2aaSAndroid Build Coastguard Worker         canvas->save();
408*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(20, 150);
409*c8dee2aaSAndroid Build Coastguard Worker             this->drawRow(dContext, canvas, 0.25f);
410*c8dee2aaSAndroid Build Coastguard Worker         canvas->restore();
411*c8dee2aaSAndroid Build Coastguard Worker 
412*c8dee2aaSAndroid Build Coastguard Worker         canvas->save();
413*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(20, 220);
414*c8dee2aaSAndroid Build Coastguard Worker             this->drawRow(dContext, canvas, 2.0f);
415*c8dee2aaSAndroid Build Coastguard Worker         canvas->restore();
416*c8dee2aaSAndroid Build Coastguard Worker 
417*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
418*c8dee2aaSAndroid Build Coastguard Worker     }
419*c8dee2aaSAndroid Build Coastguard Worker 
420*c8dee2aaSAndroid Build Coastguard Worker private:
421*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = skiagm::GM;
422*c8dee2aaSAndroid Build Coastguard Worker };
423*c8dee2aaSAndroid Build Coastguard Worker 
424*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator, false); )
425*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator, false); )
426*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator, true); )
427