Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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;
84 draw_something(recorder.beginRecording(bounds), bounds);
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
91 SkMatrix matrix;
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) {
136 SkMatrix matrix;
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
217 if (policy == GrImageTexGenPolicy::kDraw) {
218 return view;
219 }
220 auto budgeted = policy == GrImageTexGenPolicy::kNew_Uncached_Unbudgeted
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;
274 draw_something(recorder.beginRecording(bounds), bounds);
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] =
359 skgpu::ganesh::AsView(canvas->recordingContext(), image, skgpu::Mipmapped::kNo);
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)
@ 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)
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
SkString getName() const override
void onOnceBeforeDraw() override
void drawRow(GrDirectContext *dContext, SkCanvas *canvas, float scale) const
static void draw_as_tex(SkCanvas *canvas, SkImage *image, SkScalar x, SkScalar y)
SkISize getISize() override
ImageCacheratorGM(const char suffix[], FactoryFunc factory, bool useTexture)
static void draw_placeholder(SkCanvas *canvas, SkScalar x, SkScalar y, int w, int h)
bool makeCaches(SkCanvas *canvas)
static void draw_as_bitmap(GrDirectContext *dContext, SkCanvas *canvas, SkImage *image, SkScalar x, SkScalar y)
SkISize getISize() override
void onDraw(SkCanvas *canvas) override
void onOnceBeforeDraw() override
SkString getName() const override
void drawSet(SkCanvas *canvas) const
bool onGetPixels(const SkImageInfo &info, void *pixels, size_t rowBytes, const Options &) override
RasterGenerator(const SkBitmap &bm)
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)
void drawOval(const SkRect &oval, const SkPaint &paint)
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
virtual GrRecordingContext * recordingContext() const
virtual skgpu::graphite::Recorder * recorder() const
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
void clear(SkColor color)
Definition SkCanvas.h:1199
int save()
Definition SkCanvas.cpp:451
void scale(SkScalar sx, SkScalar sy)
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()
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
TextureGenerator(SkCanvas *canvas, const SkImageInfo &info, sk_sp< SkPicture > pic)
T * get() const
Definition SkRefCnt.h:303
const Paint & paint
VkSurfaceKHR surface
Definition main.cc:49
sk_sp< SkImage > image
Definition examples.cpp:29
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)
static void draw_something(SkCanvas *canvas, const SkRect &bounds)
static std::unique_ptr< SkImageGenerator > make_ras_generator(SkCanvas *, sk_sp< SkPicture > pic)
static std::unique_ptr< SkImageGenerator > make_tex_generator(SkCanvas *canvas, sk_sp< SkPicture > pic)
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
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 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
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
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