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/GrContext.h"
29 #include "include/gpu/GrTypes.h"
30 #include "include/private/GrTypesPriv.h"
31 #include "src/gpu/GrContextPriv.h"
32 #include "src/gpu/GrSamplerState.h"
33 #include "src/gpu/GrSurfaceContext.h"
34 #include "src/gpu/GrTextureProxy.h"
35 #include "src/image/SkImage_Base.h"
36 #include "src/image/SkImage_Gpu.h"
37
38 #include <memory>
39 #include <utility>
40
41 class GrRecordingContext;
42
draw_something(SkCanvas * canvas,const SkRect & bounds)43 static void draw_something(SkCanvas* canvas, const SkRect& bounds) {
44 SkPaint paint;
45 paint.setAntiAlias(true);
46 paint.setColor(SK_ColorRED);
47 paint.setStyle(SkPaint::kStroke_Style);
48 paint.setStrokeWidth(10);
49 canvas->drawRect(bounds, paint);
50 paint.setStyle(SkPaint::kFill_Style);
51 paint.setColor(SK_ColorBLUE);
52 canvas->drawOval(bounds, paint);
53 }
54
55 /*
56 * Exercise drawing pictures inside an image, showing that the image version is pixelated
57 * (correctly) when it is inside an image.
58 */
59 class ImagePictGM : public skiagm::GM {
60 sk_sp<SkPicture> fPicture;
61 sk_sp<SkImage> fImage0;
62 sk_sp<SkImage> fImage1;
63 public:
ImagePictGM()64 ImagePictGM() {}
65
66 protected:
onShortName()67 SkString onShortName() override {
68 return SkString("image-picture");
69 }
70
onISize()71 SkISize onISize() override {
72 return SkISize::Make(850, 450);
73 }
74
onOnceBeforeDraw()75 void onOnceBeforeDraw() override {
76 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
77 SkPictureRecorder recorder;
78 draw_something(recorder.beginRecording(bounds), bounds);
79 fPicture = recorder.finishRecordingAsPicture();
80
81 // extract enough just for the oval.
82 const SkISize size = SkISize::Make(100, 100);
83 auto srgbColorSpace = SkColorSpace::MakeSRGB();
84
85 SkMatrix matrix;
86 matrix.setTranslate(-100, -100);
87 fImage0 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
88 SkImage::BitDepth::kU8, srgbColorSpace);
89 matrix.postTranslate(-50, -50);
90 matrix.postRotate(45);
91 matrix.postTranslate(50, 50);
92 fImage1 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
93 SkImage::BitDepth::kU8, srgbColorSpace);
94 }
95
drawSet(SkCanvas * canvas) const96 void drawSet(SkCanvas* canvas) const {
97 SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
98 canvas->drawPicture(fPicture, &matrix, nullptr);
99 canvas->drawImage(fImage0.get(), 150, 0);
100 canvas->drawImage(fImage1.get(), 300, 0);
101 }
102
onDraw(SkCanvas * canvas)103 void onDraw(SkCanvas* canvas) override {
104 canvas->translate(20, 20);
105
106 this->drawSet(canvas);
107
108 canvas->save();
109 canvas->translate(0, 130);
110 canvas->scale(0.25f, 0.25f);
111 this->drawSet(canvas);
112 canvas->restore();
113
114 canvas->save();
115 canvas->translate(0, 200);
116 canvas->scale(2, 2);
117 this->drawSet(canvas);
118 canvas->restore();
119 }
120
121 private:
122 typedef skiagm::GM INHERITED;
123 };
DEF_GM(return new ImagePictGM;)124 DEF_GM( return new ImagePictGM; )
125
126 ///////////////////////////////////////////////////////////////////////////////////////////////////
127
128 static std::unique_ptr<SkImageGenerator> make_pic_generator(GrContext*, sk_sp<SkPicture> pic) {
129 SkMatrix matrix;
130 matrix.setTranslate(-100, -100);
131 return SkImageGenerator::MakeFromPicture({ 100, 100 }, std::move(pic), &matrix, nullptr,
132 SkImage::BitDepth::kU8,
133 SkColorSpace::MakeSRGB());
134 }
135
136 class RasterGenerator : public SkImageGenerator {
137 public:
RasterGenerator(const SkBitmap & bm)138 RasterGenerator(const SkBitmap& bm) : SkImageGenerator(bm.info()), fBM(bm)
139 {}
140
141 protected:
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options &)142 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
143 const Options&) override {
144 SkASSERT(fBM.width() == info.width());
145 SkASSERT(fBM.height() == info.height());
146 return fBM.readPixels(info, pixels, rowBytes, 0, 0);
147 }
148 private:
149 SkBitmap fBM;
150 };
make_ras_generator(GrContext *,sk_sp<SkPicture> pic)151 static std::unique_ptr<SkImageGenerator> make_ras_generator(GrContext*, sk_sp<SkPicture> pic) {
152 SkBitmap bm;
153 bm.allocN32Pixels(100, 100);
154 SkCanvas canvas(bm);
155 canvas.clear(0);
156 canvas.translate(-100, -100);
157 canvas.drawPicture(pic);
158 return std::make_unique<RasterGenerator>(bm);
159 }
160
161 class EmptyGenerator : public SkImageGenerator {
162 public:
EmptyGenerator(const SkImageInfo & info)163 EmptyGenerator(const SkImageInfo& info) : SkImageGenerator(info) {}
164 };
165
166 class TextureGenerator : public SkImageGenerator {
167 public:
TextureGenerator(GrContext * ctx,const SkImageInfo & info,sk_sp<SkPicture> pic)168 TextureGenerator(GrContext* ctx, const SkImageInfo& info, sk_sp<SkPicture> pic)
169 : SkImageGenerator(info)
170 , fCtx(SkRef(ctx)) {
171
172 sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, info, 0,
173 kTopLeft_GrSurfaceOrigin, nullptr));
174 if (surface) {
175 surface->getCanvas()->clear(0);
176 surface->getCanvas()->translate(-100, -100);
177 surface->getCanvas()->drawPicture(pic);
178 sk_sp<SkImage> image(surface->makeImageSnapshot());
179 const GrSurfaceProxyView* view = as_IB(image)->view(fCtx.get());
180 if (view) {
181 fView = *view;
182 }
183 }
184 }
185 protected:
onGenerateTexture(GrRecordingContext * ctx,const SkImageInfo & info,const SkIPoint & origin,bool willBeMipped)186 GrSurfaceProxyView onGenerateTexture(GrRecordingContext* ctx, const SkImageInfo& info,
187 const SkIPoint& origin,
188 bool willBeMipped) override {
189 SkASSERT(ctx);
190 SkASSERT(ctx == fCtx.get());
191
192 if (!fView) {
193 return {};
194 }
195
196 if (origin.fX == 0 && origin.fY == 0 && info.dimensions() == fView.proxy()->dimensions()) {
197 return fView;
198 }
199
200 GrMipMapped mipMapped = willBeMipped ? GrMipMapped::kYes : GrMipMapped::kNo;
201
202 // TODO: When we update this function to return a view instead of just a proxy then we can
203 // remove the extra ref that happens when we call asTextureProxyRef.
204 return GrSurfaceProxy::Copy(
205 fCtx.get(), fView.proxy(), fView.origin(),
206 SkColorTypeToGrColorType(info.colorType()), mipMapped,
207 SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height()),
208 SkBackingFit::kExact, SkBudgeted::kYes);
209 }
210
211 private:
212 sk_sp<GrContext> fCtx;
213 GrSurfaceProxyView fView;
214 };
215
make_tex_generator(GrContext * ctx,sk_sp<SkPicture> pic)216 static std::unique_ptr<SkImageGenerator> make_tex_generator(GrContext* ctx, sk_sp<SkPicture> pic) {
217 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
218
219 if (!ctx) {
220 return std::make_unique<EmptyGenerator>(info);
221 }
222 return std::make_unique<TextureGenerator>(ctx, info, pic);
223 }
224
225 class ImageCacheratorGM : public skiagm::GM {
226 SkString fName;
227 std::unique_ptr<SkImageGenerator> (*fFactory)(GrContext*, sk_sp<SkPicture>);
228 sk_sp<SkPicture> fPicture;
229 sk_sp<SkImage> fImage;
230 sk_sp<SkImage> fImageSubset;
231
232 public:
ImageCacheratorGM(const char suffix[],std::unique_ptr<SkImageGenerator> (* factory)(GrContext *,sk_sp<SkPicture>))233 ImageCacheratorGM(const char suffix[],
234 std::unique_ptr<SkImageGenerator> (*factory)(GrContext*, sk_sp<SkPicture>))
235 : fFactory(factory)
236 {
237 fName.printf("image-cacherator-from-%s", suffix);
238 }
239
240 protected:
onShortName()241 SkString onShortName() override {
242 return fName;
243 }
244
onISize()245 SkISize onISize() override {
246 return SkISize::Make(960, 450);
247 }
248
onOnceBeforeDraw()249 void onOnceBeforeDraw() override {
250 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
251 SkPictureRecorder recorder;
252 draw_something(recorder.beginRecording(bounds), bounds);
253 fPicture = recorder.finishRecordingAsPicture();
254 }
255
makeCaches(GrContext * ctx)256 void makeCaches(GrContext* ctx) {
257 auto gen = fFactory(ctx, fPicture);
258 fImage = SkImage::MakeFromGenerator(std::move(gen));
259
260 const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
261
262 gen = fFactory(ctx, fPicture);
263 fImageSubset = SkImage::MakeFromGenerator(std::move(gen), &subset);
264
265 SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
266 SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
267 }
268
draw_as_bitmap(SkCanvas * canvas,SkImage * image,SkScalar x,SkScalar y)269 static void draw_as_bitmap(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
270 SkBitmap bitmap;
271 as_IB(image)->getROPixels(&bitmap);
272 canvas->drawBitmap(bitmap, x, y);
273 }
274
draw_as_tex(SkCanvas * canvas,SkImage * image,SkScalar x,SkScalar y)275 static void draw_as_tex(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
276 GrSurfaceProxyView view = as_IB(image)->refView(canvas->getGrContext(),
277 GrSamplerState::Filter::kBilerp, nullptr);
278 if (!view) {
279 // show placeholder if we have no texture
280 SkPaint paint;
281 paint.setStyle(SkPaint::kStroke_Style);
282 SkRect r = SkRect::MakeXYWH(x, y, SkIntToScalar(image->width()),
283 SkIntToScalar(image->width()));
284 canvas->drawRect(r, paint);
285 canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
286 canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
287 return;
288 }
289
290 // No API to draw a GrTexture directly, so we cheat and create a private image subclass
291 sk_sp<SkImage> texImage(new SkImage_Gpu(sk_ref_sp(canvas->getGrContext()),
292 image->uniqueID(), std::move(view),
293 image->colorType(), image->alphaType(),
294 image->refColorSpace()));
295 canvas->drawImage(texImage.get(), x, y);
296 }
297
drawSet(SkCanvas * canvas) const298 void drawSet(SkCanvas* canvas) const {
299 SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
300 canvas->drawPicture(fPicture, &matrix, nullptr);
301
302 // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This
303 // way we also can force the generateTexture call.
304
305 draw_as_tex(canvas, fImage.get(), 310, 0);
306 draw_as_tex(canvas, fImageSubset.get(), 310+101, 0);
307
308 draw_as_bitmap(canvas, fImage.get(), 150, 0);
309 draw_as_bitmap(canvas, fImageSubset.get(), 150+101, 0);
310 }
311
onDraw(SkCanvas * canvas)312 void onDraw(SkCanvas* canvas) override {
313 this->makeCaches(canvas->getGrContext());
314
315 canvas->translate(20, 20);
316
317 this->drawSet(canvas);
318
319 canvas->save();
320 canvas->translate(0, 130);
321 canvas->scale(0.25f, 0.25f);
322 this->drawSet(canvas);
323 canvas->restore();
324
325 canvas->save();
326 canvas->translate(0, 200);
327 canvas->scale(2, 2);
328 this->drawSet(canvas);
329 canvas->restore();
330 }
331
332 private:
333 typedef skiagm::GM INHERITED;
334 };
335 DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator); )
336 DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator); )
337 DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator); )
338