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/core/SkMakeUnique.h"
32 #include "src/gpu/GrContextPriv.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::MakeTrans(-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 typedef skiagm::GM INHERITED;
124 };
DEF_GM(return new ImagePictGM;)125 DEF_GM( return new ImagePictGM; )
126
127 ///////////////////////////////////////////////////////////////////////////////////////////////////
128
129 static std::unique_ptr<SkImageGenerator> make_pic_generator(GrContext*, sk_sp<SkPicture> pic) {
130 SkMatrix matrix;
131 matrix.setTranslate(-100, -100);
132 return SkImageGenerator::MakeFromPicture({ 100, 100 }, std::move(pic), &matrix, nullptr,
133 SkImage::BitDepth::kU8,
134 SkColorSpace::MakeSRGB());
135 }
136
137 class RasterGenerator : public SkImageGenerator {
138 public:
RasterGenerator(const SkBitmap & bm)139 RasterGenerator(const SkBitmap& bm) : SkImageGenerator(bm.info()), fBM(bm)
140 {}
141
142 protected:
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options &)143 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
144 const Options&) override {
145 SkASSERT(fBM.width() == info.width());
146 SkASSERT(fBM.height() == info.height());
147 return fBM.readPixels(info, pixels, rowBytes, 0, 0);
148 }
149 private:
150 SkBitmap fBM;
151 };
make_ras_generator(GrContext *,sk_sp<SkPicture> pic)152 static std::unique_ptr<SkImageGenerator> make_ras_generator(GrContext*, sk_sp<SkPicture> pic) {
153 SkBitmap bm;
154 bm.allocN32Pixels(100, 100);
155 SkCanvas canvas(bm);
156 canvas.clear(0);
157 canvas.translate(-100, -100);
158 canvas.drawPicture(pic);
159 return skstd::make_unique<RasterGenerator>(bm);
160 }
161
162 class EmptyGenerator : public SkImageGenerator {
163 public:
EmptyGenerator(const SkImageInfo & info)164 EmptyGenerator(const SkImageInfo& info) : SkImageGenerator(info) {}
165 };
166
167 class TextureGenerator : public SkImageGenerator {
168 public:
TextureGenerator(GrContext * ctx,const SkImageInfo & info,sk_sp<SkPicture> pic)169 TextureGenerator(GrContext* ctx, const SkImageInfo& info, sk_sp<SkPicture> pic)
170 : SkImageGenerator(info)
171 , fCtx(SkRef(ctx)) {
172
173 sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, info, 0,
174 kTopLeft_GrSurfaceOrigin, nullptr));
175 if (surface) {
176 surface->getCanvas()->clear(0);
177 surface->getCanvas()->translate(-100, -100);
178 surface->getCanvas()->drawPicture(pic);
179 sk_sp<SkImage> image(surface->makeImageSnapshot());
180 fProxy = as_IB(image)->asTextureProxyRef(fCtx.get());
181 }
182 }
183 protected:
onGenerateTexture(GrRecordingContext * ctx,const SkImageInfo & info,const SkIPoint & origin,bool willBeMipped)184 sk_sp<GrTextureProxy> onGenerateTexture(GrRecordingContext* ctx, const SkImageInfo& info,
185 const SkIPoint& origin,
186 bool willBeMipped) override {
187 SkASSERT(ctx);
188 SkASSERT(ctx == fCtx.get());
189
190 if (!fProxy) {
191 return nullptr;
192 }
193
194 if (origin.fX == 0 && origin.fY == 0 &&
195 info.width() == fProxy->width() && info.height() == fProxy->height()) {
196 return fProxy;
197 }
198
199 GrMipMapped mipMapped = willBeMipped ? GrMipMapped::kYes : GrMipMapped::kNo;
200
201 return GrSurfaceProxy::Copy(fCtx.get(), fProxy.get(), mipMapped,
202 SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height()),
203 SkBackingFit::kExact, SkBudgeted::kYes);
204 }
205
206 private:
207 sk_sp<GrContext> fCtx;
208 sk_sp<GrTextureProxy> fProxy;
209 };
210
make_tex_generator(GrContext * ctx,sk_sp<SkPicture> pic)211 static std::unique_ptr<SkImageGenerator> make_tex_generator(GrContext* ctx, sk_sp<SkPicture> pic) {
212 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
213
214 if (!ctx) {
215 return skstd::make_unique<EmptyGenerator>(info);
216 }
217 return skstd::make_unique<TextureGenerator>(ctx, info, pic);
218 }
219
220 class ImageCacheratorGM : public skiagm::GM {
221 SkString fName;
222 std::unique_ptr<SkImageGenerator> (*fFactory)(GrContext*, sk_sp<SkPicture>);
223 sk_sp<SkPicture> fPicture;
224 sk_sp<SkImage> fImage;
225 sk_sp<SkImage> fImageSubset;
226
227 public:
ImageCacheratorGM(const char suffix[],std::unique_ptr<SkImageGenerator> (* factory)(GrContext *,sk_sp<SkPicture>))228 ImageCacheratorGM(const char suffix[],
229 std::unique_ptr<SkImageGenerator> (*factory)(GrContext*, sk_sp<SkPicture>))
230 : fFactory(factory)
231 {
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(GrContext * ctx)251 void makeCaches(GrContext* ctx) {
252 auto gen = fFactory(ctx, fPicture);
253 fImage = SkImage::MakeFromGenerator(std::move(gen));
254
255 const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
256
257 gen = fFactory(ctx, fPicture);
258 fImageSubset = SkImage::MakeFromGenerator(std::move(gen), &subset);
259
260 SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
261 SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
262 }
263
draw_as_bitmap(SkCanvas * canvas,SkImage * image,SkScalar x,SkScalar y)264 static void draw_as_bitmap(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
265 SkBitmap bitmap;
266 as_IB(image)->getROPixels(&bitmap);
267 canvas->drawBitmap(bitmap, x, y);
268 }
269
draw_as_tex(SkCanvas * canvas,SkImage * image,SkScalar x,SkScalar y)270 static void draw_as_tex(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
271 sk_sp<GrTextureProxy> proxy(as_IB(image)->asTextureProxyRef(
272 canvas->getGrContext(), GrSamplerState::ClampBilerp(), nullptr));
273 if (!proxy) {
274 // show placeholder if we have no texture
275 SkPaint paint;
276 paint.setStyle(SkPaint::kStroke_Style);
277 SkRect r = SkRect::MakeXYWH(x, y, SkIntToScalar(image->width()),
278 SkIntToScalar(image->width()));
279 canvas->drawRect(r, paint);
280 canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
281 canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
282 return;
283 }
284
285 // No API to draw a GrTexture directly, so we cheat and create a private image subclass
286 sk_sp<SkImage> texImage(new SkImage_Gpu(sk_ref_sp(canvas->getGrContext()),
287 image->uniqueID(), kPremul_SkAlphaType,
288 std::move(proxy), image->refColorSpace()));
289 canvas->drawImage(texImage.get(), x, y);
290 }
291
drawSet(SkCanvas * canvas) const292 void drawSet(SkCanvas* canvas) const {
293 SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
294 canvas->drawPicture(fPicture, &matrix, nullptr);
295
296 // Draw the tex first, so it doesn't hit a lucky cache from the raster version. This
297 // way we also can force the generateTexture call.
298
299 draw_as_tex(canvas, fImage.get(), 310, 0);
300 draw_as_tex(canvas, fImageSubset.get(), 310+101, 0);
301
302 draw_as_bitmap(canvas, fImage.get(), 150, 0);
303 draw_as_bitmap(canvas, fImageSubset.get(), 150+101, 0);
304 }
305
onDraw(SkCanvas * canvas)306 void onDraw(SkCanvas* canvas) override {
307 this->makeCaches(canvas->getGrContext());
308
309 canvas->translate(20, 20);
310
311 this->drawSet(canvas);
312
313 canvas->save();
314 canvas->translate(0, 130);
315 canvas->scale(0.25f, 0.25f);
316 this->drawSet(canvas);
317 canvas->restore();
318
319 canvas->save();
320 canvas->translate(0, 200);
321 canvas->scale(2, 2);
322 this->drawSet(canvas);
323 canvas->restore();
324 }
325
326 private:
327 typedef skiagm::GM INHERITED;
328 };
329 DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator); )
330 DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator); )
331 DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator); )
332