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