Flutter Engine
The Flutter Engine
image_pict.cpp
Go to the documentation of this file.
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"
21#include "include/core/SkRect.h"
24#include "include/core/SkSize.h"
30#include "include/gpu/GrTypes.h"
43
44#include <memory>
45#include <utility>
46
47#if defined(SK_GRAPHITE)
49#endif
50
52
53static void draw_something(SkCanvas* canvas, const SkRect& bounds) {
55 paint.setAntiAlias(true);
56 paint.setColor(SK_ColorRED);
58 paint.setStrokeWidth(10);
59 canvas->drawRect(bounds, paint);
61 paint.setColor(SK_ColorBLUE);
62 canvas->drawOval(bounds, paint);
63}
64
65/*
66 * Exercise drawing pictures inside an image, showing that the image version is pixelated
67 * (correctly) when it is inside an image.
68 */
69class ImagePictGM : public skiagm::GM {
70 sk_sp<SkPicture> fPicture;
71 sk_sp<SkImage> fImage0;
72 sk_sp<SkImage> fImage1;
73public:
75
76protected:
77 SkString getName() const override { return SkString("image-picture"); }
78
79 SkISize getISize() override { return SkISize::Make(850, 450); }
80
81 void onOnceBeforeDraw() override {
82 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
83 SkPictureRecorder recorder;
85 fPicture = recorder.finishRecordingAsPicture();
86
87 // extract enough just for the oval.
88 const SkISize size = SkISize::Make(100, 100);
89 auto srgbColorSpace = SkColorSpace::MakeSRGB();
90
92 matrix.setTranslate(-100, -100);
94 fPicture, size, &matrix, nullptr, SkImages::BitDepth::kU8, srgbColorSpace);
95 matrix.postTranslate(-50, -50);
96 matrix.postRotate(45);
97 matrix.postTranslate(50, 50);
99 fPicture, size, &matrix, nullptr, SkImages::BitDepth::kU8, srgbColorSpace);
100 }
101
102 void drawSet(SkCanvas* canvas) const {
103 SkMatrix matrix = SkMatrix::Translate(-100, -100);
104 canvas->drawPicture(fPicture, &matrix, nullptr);
105 canvas->drawImage(fImage0.get(), 150, 0);
106 canvas->drawImage(fImage1.get(), 300, 0);
107 }
108
109 void onDraw(SkCanvas* canvas) override {
110 canvas->translate(20, 20);
111
112 this->drawSet(canvas);
113
114 canvas->save();
115 canvas->translate(0, 130);
116 canvas->scale(0.25f, 0.25f);
117 this->drawSet(canvas);
118 canvas->restore();
119
120 canvas->save();
121 canvas->translate(0, 200);
122 canvas->scale(2, 2);
123 this->drawSet(canvas);
124 canvas->restore();
125 }
126
127private:
128 using INHERITED = skiagm::GM;
129};
130DEF_GM( return new ImagePictGM; )
131
132///////////////////////////////////////////////////////////////////////////////////////////////////
133
134static std::unique_ptr<SkImageGenerator> make_pic_generator(SkCanvas*,
135 sk_sp<SkPicture> pic) {
137 matrix.setTranslate(-100, -100);
138 return SkImageGenerators::MakeFromPicture({100, 100},
139 std::move(pic),
140 &matrix,
141 nullptr,
144}
145
147public:
148 RasterGenerator(const SkBitmap& bm) : SkImageGenerator(bm.info()), fBM(bm)
149 {}
150
151protected:
152 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
153 const Options&) override {
154 SkASSERT(fBM.width() == info.width());
155 SkASSERT(fBM.height() == info.height());
156 return fBM.readPixels(info, pixels, rowBytes, 0, 0);
157 }
158private:
159 SkBitmap fBM;
160};
161static std::unique_ptr<SkImageGenerator> make_ras_generator(SkCanvas*,
162 sk_sp<SkPicture> pic) {
163 SkBitmap bm;
164 bm.allocN32Pixels(100, 100);
165 SkCanvas canvas(bm);
166 canvas.clear(0);
167 canvas.translate(-100, -100);
168 canvas.drawPicture(pic);
169 return std::make_unique<RasterGenerator>(bm);
170}
171
173public:
176
177 fRContext = sk_ref_sp(canvas->recordingContext());
178
180
181 if (fRContext) {
184 info,
185 0,
187 nullptr);
188 }
189#if defined(SK_GRAPHITE)
190 if (skgpu::graphite::Recorder* recorder = canvas->recorder()) {
192 }
193#endif
194
195 if (surface) {
196 surface->getCanvas()->clear(0);
197 surface->getCanvas()->translate(-100, -100);
198 surface->getCanvas()->drawPicture(pic);
199 fImage = surface->makeImageSnapshot();
200 }
201 }
202protected:
204 const SkImageInfo& info,
205 skgpu::Mipmapped mipmapped,
206 GrImageTexGenPolicy policy) override {
207 SkASSERT(rContext);
208 SkASSERT(rContext->priv().matches(fRContext.get()));
209
210 auto [view, _] = skgpu::ganesh::AsView(rContext, fImage, skgpu::Mipmapped::kNo);
211 if (!view) {
212 return {};
213 }
214
215 SkASSERT_RELEASE(info.dimensions() == view.proxy()->dimensions());
216
218 return view;
219 }
224 fRContext.get(),
225 view,
226 mipmapped,
227 SkIRect::MakeWH(info.width(), info.height()),
229 budgeted,
230 /*label=*/"SurfaceProxyView_GenerateTexture");
231 }
232
233private:
235 sk_sp<SkImage> fImage;
236};
237
238static std::unique_ptr<SkImageGenerator> make_tex_generator(SkCanvas* canvas,
239 sk_sp<SkPicture> pic) {
240 auto dContext = GrAsDirectContext(canvas->recordingContext());
241 if (!dContext && !canvas->recorder()) {
242 return nullptr;
243 }
244
246
247 return std::make_unique<TextureGenerator>(canvas, info, pic);
248}
249
251 typedef std::unique_ptr<SkImageGenerator> (*FactoryFunc)(SkCanvas*, sk_sp<SkPicture>);
252
253 SkString fName;
254 FactoryFunc fFactory;
255 sk_sp<SkPicture> fPicture;
256 sk_sp<SkImage> fImage;
257 sk_sp<SkImage> fImageSubset;
258 bool fUseTexture;
259
260public:
261 ImageCacheratorGM(const char suffix[], FactoryFunc factory, bool useTexture) :
262 fFactory(factory), fUseTexture(useTexture) {
263 fName.printf("image-cacherator-from-%s", suffix);
264 }
265
266protected:
267 SkString getName() const override { return fName; }
268
269 SkISize getISize() override { return SkISize::Make(960, 450); }
270
271 void onOnceBeforeDraw() override {
272 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
273 SkPictureRecorder recorder;
275 fPicture = recorder.finishRecordingAsPicture();
276 }
277
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 if (fUseTexture) {
287 auto textureGen = std::unique_ptr<GrTextureGenerator>(
288 static_cast<GrTextureGenerator*>(gen.release()));
289 fImage = SkImages::DeferredFromTextureGenerator(std::move(textureGen));
290 } else {
291 fImage = SkImages::DeferredFromGenerator(std::move(gen));
292 }
293 if (!fImage) {
294 return false;
295 }
296 SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
297 }
298
299 {
300 const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
301
302 // We re-create the generator here on the off chance that making a subset from
303 // 'fImage' might perturb its state.
304 auto gen = fFactory(canvas, fPicture);
305 if (!gen) {
306 return false;
307 }
308
309 if (dContext) {
310 if (fUseTexture) {
311 auto textureGen = std::unique_ptr<GrTextureGenerator>(
312 static_cast<GrTextureGenerator*>(gen.release()));
313 fImageSubset = SkImages::DeferredFromTextureGenerator(std::move(textureGen))
314 ->makeSubset(dContext, subset);
315 } else {
316 fImageSubset = SkImages::DeferredFromGenerator(std::move(gen))
317 ->makeSubset(dContext, subset);
318 }
319 } else {
320#if defined(SK_GRAPHITE)
321 auto recorder = canvas->recorder();
322 fImageSubset = SkImages::DeferredFromGenerator(std::move(gen))
323 ->makeSubset(recorder, subset, {});
324#endif
325 }
326 if (!fImageSubset) {
327 return false;
328 }
329 SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
330 }
331
332 return true;
333 }
334
335 static void draw_placeholder(SkCanvas* canvas, SkScalar x, SkScalar y, int w, int h) {
339 canvas->drawRect(r, paint);
340 canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
341 canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
342 }
343
344 static void draw_as_bitmap(GrDirectContext* dContext, SkCanvas* canvas, SkImage* image,
345 SkScalar x, SkScalar y) {
347 if (as_IB(image)->getROPixels(dContext, &bitmap)) {
348 canvas->drawImage(bitmap.asImage(), x, y);
349 } else {
350 draw_placeholder(canvas, x, y, image->width(), image->height());
351 }
352 }
353
355 if (as_IB(image)->isGaneshBacked()) {
356 // The gpu-backed images are drawn in this manner bc the generator backed images
357 // aren't considered texture-backed
358 auto [view, ct] =
360 if (!view) {
361 // show placeholder if we have no texture
362 draw_placeholder(canvas, x, y, image->width(), image->height());
363 return;
364 }
366 image->alphaType(),
368 // No API to draw a GrTexture directly, so we cheat and create a private image subclass
370 image->uniqueID(),
371 std::move(view),
372 std::move(colorInfo)));
373 canvas->drawImage(texImage.get(), x, y);
374 } else {
375 canvas->drawImage(image, x, y);
376 }
377 }
378
379 void drawRow(GrDirectContext* dContext, SkCanvas* canvas, float scale) const {
380 canvas->scale(scale, scale);
381
382 SkMatrix matrix = SkMatrix::Translate(-100, -100);
383 canvas->drawPicture(fPicture, &matrix, nullptr);
384
385 // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This
386 // way we also can force the generateTexture call.
387
388 draw_as_tex(canvas, fImage.get(), 150, 0);
389 draw_as_tex(canvas, fImageSubset.get(), 150+101, 0);
390
391 draw_as_bitmap(dContext, canvas, fImage.get(), 310, 0);
392 draw_as_bitmap(dContext, canvas, fImageSubset.get(), 310+101, 0);
393 }
394
395 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
396 auto dContext = GrAsDirectContext(canvas->recordingContext());
397 if (!this->makeCaches(canvas)) {
398 errorMsg->printf("Could not create cached images");
399 return DrawResult::kSkip;
400 }
401
402 canvas->save();
403 canvas->translate(20, 20);
404 this->drawRow(dContext, canvas, 1.0);
405 canvas->restore();
406
407 canvas->save();
408 canvas->translate(20, 150);
409 this->drawRow(dContext, canvas, 0.25f);
410 canvas->restore();
411
412 canvas->save();
413 canvas->translate(20, 220);
414 this->drawRow(dContext, canvas, 2.0f);
415 canvas->restore();
416
417 return DrawResult::kOk;
418 }
419
420private:
421 using INHERITED = skiagm::GM;
422};
423
424DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator, false); )
425DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator, false); )
426DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator, true); )
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
const char * fName
static GrDirectContext * GrAsDirectContext(GrContext_Base *base)
static constexpr SkColorType GrColorTypeToSkColorType(GrColorType ct)
Definition: GrTypesPriv.h:589
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
#define SkASSERT_RELEASE(cond)
Definition: SkAssert.h:100
#define SkASSERT(cond)
Definition: SkAssert.h:116
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
GrImageTexGenPolicy
Definition: SkGr.h:141
static SkImage_Base * as_IB(SkImage *image)
Definition: SkImage_Base.h:201
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
#define SkIntToScalar(x)
Definition: SkScalar.h:57
bool matches(GrContext_Base *candidate) const
GrRecordingContextPriv priv()
static GrSurfaceProxyView Copy(GrRecordingContext *context, GrSurfaceProxyView src, skgpu::Mipmapped mipmapped, SkIRect srcRect, SkBackingFit fit, skgpu::Budgeted budgeted, std::string_view label)
DrawResult onDraw(SkCanvas *canvas, SkString *errorMsg) override
Definition: image_pict.cpp:395
SkString getName() const override
Definition: image_pict.cpp:267
void onOnceBeforeDraw() override
Definition: image_pict.cpp:271
void drawRow(GrDirectContext *dContext, SkCanvas *canvas, float scale) const
Definition: image_pict.cpp:379
static void draw_as_tex(SkCanvas *canvas, SkImage *image, SkScalar x, SkScalar y)
Definition: image_pict.cpp:354
SkISize getISize() override
Definition: image_pict.cpp:269
ImageCacheratorGM(const char suffix[], FactoryFunc factory, bool useTexture)
Definition: image_pict.cpp:261
static void draw_placeholder(SkCanvas *canvas, SkScalar x, SkScalar y, int w, int h)
Definition: image_pict.cpp:335
bool makeCaches(SkCanvas *canvas)
Definition: image_pict.cpp:278
static void draw_as_bitmap(GrDirectContext *dContext, SkCanvas *canvas, SkImage *image, SkScalar x, SkScalar y)
Definition: image_pict.cpp:344
SkISize getISize() override
Definition: image_pict.cpp:79
void onDraw(SkCanvas *canvas) override
Definition: image_pict.cpp:109
void onOnceBeforeDraw() override
Definition: image_pict.cpp:81
SkString getName() const override
Definition: image_pict.cpp:77
void drawSet(SkCanvas *canvas) const
Definition: image_pict.cpp:102
bool onGetPixels(const SkImageInfo &info, void *pixels, size_t rowBytes, const Options &) override
Definition: image_pict.cpp:152
RasterGenerator(const SkBitmap &bm)
Definition: image_pict.cpp:148
int width() const
Definition: SkBitmap.h:149
bool readPixels(const SkImageInfo &dstInfo, void *dstPixels, size_t dstRowBytes, int srcX, int srcY) const
Definition: SkBitmap.cpp:488
void allocN32Pixels(int width, int height, bool isOpaque=false)
Definition: SkBitmap.cpp:232
int height() const
Definition: SkBitmap.h:158
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawOval(const SkRect &oval, const SkPaint &paint)
Definition: SkCanvas.cpp:1698
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
virtual GrRecordingContext * recordingContext() const
Definition: SkCanvas.cpp:1637
virtual skgpu::graphite::Recorder * recorder() const
Definition: SkCanvas.cpp:1641
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
Definition: SkCanvas.cpp:2700
void clear(SkColor color)
Definition: SkCanvas.h:1199
int save()
Definition: SkCanvas.cpp:447
void scale(SkScalar sx, SkScalar sy)
Definition: SkCanvas.cpp:1289
void drawPicture(const SkPicture *picture)
Definition: SkCanvas.h:1961
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition: SkCanvas.h:1528
static sk_sp< SkColorSpace > MakeSRGB()
SkISize dimensions() const
Definition: SkImage.h:297
uint32_t uniqueID() const
Definition: SkImage.h:311
SkAlphaType alphaType() const
Definition: SkImage.cpp:154
int width() const
Definition: SkImage.h:285
int height() const
Definition: SkImage.h:291
sk_sp< SkColorSpace > refColorSpace() const
Definition: SkImage.cpp:158
virtual sk_sp< SkImage > makeSubset(GrDirectContext *direct, const SkIRect &subset) const =0
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
@ kFill_Style
set to fill geometry
Definition: SkPaint.h:193
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
void printf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:534
GrSurfaceProxyView onGenerateTexture(GrRecordingContext *rContext, const SkImageInfo &info, skgpu::Mipmapped mipmapped, GrImageTexGenPolicy policy) override
Definition: image_pict.cpp:203
TextureGenerator(SkCanvas *canvas, const SkImageInfo &info, sk_sp< SkPicture > pic)
Definition: image_pict.cpp:174
T * get() const
Definition: SkRefCnt.h:303
Definition: gm.h:110
const Paint & paint
Definition: color_source.cc:38
VkSurfaceKHR surface
Definition: main.cc:49
float SkScalar
Definition: extension.cpp:12
#define DEF_GM(CODE)
Definition: gm.h:40
static std::unique_ptr< SkImageGenerator > make_pic_generator(SkCanvas *, sk_sp< SkPicture > pic)
Definition: image_pict.cpp:134
static void draw_something(SkCanvas *canvas, const SkRect &bounds)
Definition: image_pict.cpp:53
static std::unique_ptr< SkImageGenerator > make_ras_generator(SkCanvas *, sk_sp< SkPicture > pic)
Definition: image_pict.cpp:161
static std::unique_ptr< SkImageGenerator > make_tex_generator(SkCanvas *canvas, sk_sp< SkPicture > pic)
Definition: image_pict.cpp:238
double y
double x
std::unique_ptr< SkImageGenerator > MakeFromPicture(const SkISize &, sk_sp< SkPicture >, const SkMatrix *, const SkPaint *, SkImages::BitDepth, sk_sp< SkColorSpace >, SkSurfaceProps props)
SK_API sk_sp< SkImage > DeferredFromPicture(sk_sp< SkPicture > picture, const SkISize &dimensions, const SkMatrix *matrix, const SkPaint *paint, BitDepth bitDepth, sk_sp< SkColorSpace > colorSpace, SkSurfaceProps props)
SK_API sk_sp< SkImage > DeferredFromTextureGenerator(std::unique_ptr< GrTextureGenerator > gen)
SK_API sk_sp< SkImage > DeferredFromGenerator(std::unique_ptr< SkImageGenerator > imageGenerator)
@ kU8
uses 8-bit unsigned int per color component
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
sk_sp< const SkImage > image
Definition: SkRecords.h:269
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
Definition: bitmap.py:1
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network policy
Definition: switches.h:248
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: gen.py:1
std::tuple< GrSurfaceProxyView, GrColorType > AsView(GrRecordingContext *rContext, const SkImage *img, skgpu::Mipmapped mipmapped, GrImageTexGenPolicy policy)
Mipmapped
Definition: GpuTypes.h:53
DrawResult
Definition: gm.h:104
SkScalar w
SkScalar h
const Scalar scale
Definition: SkRect.h:32
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
Definition: SkRect.h:91
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition: SkRect.h:56
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
static SkImageInfo MakeN32Premul(int width, int height)
constexpr float left() const
Definition: SkRect.h:734
constexpr float top() const
Definition: SkRect.h:741
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
constexpr float right() const
Definition: SkRect.h:748
constexpr float bottom() const
Definition: SkRect.h:755