2 * Copyright 2015 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
11 #include "SkImageGenerator.h"
12 #include "SkImage_Base.h"
13 #include "SkMakeUnique.h"
14 #include "SkPictureRecorder.h"
15 #include "SkSurface.h"
18 #include "GrContext.h"
19 #include "GrContextPriv.h"
20 #include "GrSurfaceContext.h"
21 #include "GrSurfaceProxy.h"
22 #include "GrTexture.h"
23 #include "GrTextureProxy.h"
24 #include "../src/image/SkImage_Gpu.h"
27 static void draw_something(SkCanvas* canvas, const SkRect& bounds) {
29 paint.setAntiAlias(true);
30 paint.setColor(SK_ColorRED);
31 paint.setStyle(SkPaint::kStroke_Style);
32 paint.setStrokeWidth(10);
33 canvas->drawRect(bounds, paint);
34 paint.setStyle(SkPaint::kFill_Style);
35 paint.setColor(SK_ColorBLUE);
36 canvas->drawOval(bounds, paint);
40 * Exercise drawing pictures inside an image, showing that the image version is pixelated
41 * (correctly) when it is inside an image.
43 class ImagePictGM : public skiagm::GM {
44 sk_sp<SkPicture> fPicture;
45 sk_sp<SkImage> fImage0;
46 sk_sp<SkImage> fImage1;
51 SkString onShortName() override {
52 return SkString("image-picture");
55 SkISize onISize() override {
56 return SkISize::Make(850, 450);
59 void onOnceBeforeDraw() override {
60 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
61 SkPictureRecorder recorder;
62 draw_something(recorder.beginRecording(bounds), bounds);
63 fPicture = recorder.finishRecordingAsPicture();
65 // extract enough just for the oval.
66 const SkISize size = SkISize::Make(100, 100);
67 auto srgbColorSpace = SkColorSpace::MakeSRGB();
70 matrix.setTranslate(-100, -100);
71 fImage0 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
72 SkImage::BitDepth::kU8, srgbColorSpace);
73 matrix.postTranslate(-50, -50);
74 matrix.postRotate(45);
75 matrix.postTranslate(50, 50);
76 fImage1 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr,
77 SkImage::BitDepth::kU8, srgbColorSpace);
80 void drawSet(SkCanvas* canvas) const {
81 SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
82 canvas->drawPicture(fPicture, &matrix, nullptr);
83 canvas->drawImage(fImage0.get(), 150, 0);
84 canvas->drawImage(fImage1.get(), 300, 0);
87 void onDraw(SkCanvas* canvas) override {
88 canvas->translate(20, 20);
90 this->drawSet(canvas);
93 canvas->translate(0, 130);
94 canvas->scale(0.25f, 0.25f);
95 this->drawSet(canvas);
99 canvas->translate(0, 200);
101 this->drawSet(canvas);
106 typedef skiagm::GM INHERITED;
108 DEF_GM( return new ImagePictGM; )
110 ///////////////////////////////////////////////////////////////////////////////////////////////////
112 static std::unique_ptr<SkImageGenerator> make_pic_generator(GrContext*, sk_sp<SkPicture> pic) {
114 matrix.setTranslate(-100, -100);
115 return SkImageGenerator::MakeFromPicture({ 100, 100 }, std::move(pic), &matrix, nullptr,
116 SkImage::BitDepth::kU8,
117 SkColorSpace::MakeSRGB());
120 class RasterGenerator : public SkImageGenerator {
122 RasterGenerator(const SkBitmap& bm) : SkImageGenerator(bm.info()), fBM(bm)
126 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
127 const Options&) override {
128 SkASSERT(fBM.width() == info.width());
129 SkASSERT(fBM.height() == info.height());
130 return fBM.readPixels(info, pixels, rowBytes, 0, 0);
135 static std::unique_ptr<SkImageGenerator> make_ras_generator(GrContext*, sk_sp<SkPicture> pic) {
137 bm.allocN32Pixels(100, 100);
140 canvas.translate(-100, -100);
141 canvas.drawPicture(pic);
142 return skstd::make_unique<RasterGenerator>(bm);
145 class EmptyGenerator : public SkImageGenerator {
147 EmptyGenerator(const SkImageInfo& info) : SkImageGenerator(info) {}
151 class TextureGenerator : public SkImageGenerator {
153 TextureGenerator(GrContext* ctx, const SkImageInfo& info, sk_sp<SkPicture> pic)
154 : SkImageGenerator(info)
157 sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info));
159 surface->getCanvas()->clear(0);
160 surface->getCanvas()->translate(-100, -100);
161 surface->getCanvas()->drawPicture(pic);
162 sk_sp<SkImage> image(surface->makeImageSnapshot());
163 fProxy = as_IB(image)->asTextureProxyRef();
167 sk_sp<GrTextureProxy> onGenerateTexture(GrContext* ctx, const SkImageInfo& info,
168 const SkIPoint& origin) override {
170 SkASSERT(ctx == fCtx.get());
176 if (origin.fX == 0 && origin.fY == 0 &&
177 info.width() == fProxy->width() && info.height() == fProxy->height()) {
181 // need to copy the subset into a new texture
183 desc.fConfig = fProxy->config();
184 desc.fWidth = info.width();
185 desc.fHeight = info.height();
186 desc.fOrigin = fProxy->origin();
188 sk_sp<GrSurfaceContext> dstContext(fCtx->contextPriv().makeDeferredSurfaceContext(
190 SkBackingFit::kExact,
196 if (!dstContext->copy(
198 SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height()),
199 SkIPoint::Make(0, 0))) {
203 return dstContext->asTextureProxyRef();
207 sk_sp<GrContext> fCtx;
208 sk_sp<GrTextureProxy> fProxy;
211 static std::unique_ptr<SkImageGenerator> make_tex_generator(GrContext* ctx, sk_sp<SkPicture> pic) {
212 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
215 return skstd::make_unique<EmptyGenerator>(info);
217 return skstd::make_unique<TextureGenerator>(ctx, info, pic);
221 class ImageCacheratorGM : public skiagm::GM {
223 std::unique_ptr<SkImageGenerator> (*fFactory)(GrContext*, sk_sp<SkPicture>);
224 sk_sp<SkPicture> fPicture;
225 sk_sp<SkImage> fImage;
226 sk_sp<SkImage> fImageSubset;
229 ImageCacheratorGM(const char suffix[],
230 std::unique_ptr<SkImageGenerator> (*factory)(GrContext*, sk_sp<SkPicture>))
233 fName.printf("image-cacherator-from-%s", suffix);
237 SkString onShortName() override {
241 SkISize onISize() override {
242 return SkISize::Make(960, 450);
245 void onOnceBeforeDraw() override {
246 const SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100);
247 SkPictureRecorder recorder;
248 draw_something(recorder.beginRecording(bounds), bounds);
249 fPicture = recorder.finishRecordingAsPicture();
252 void makeCaches(GrContext* ctx) {
253 auto gen = fFactory(ctx, fPicture);
254 fImage = SkImage::MakeFromGenerator(std::move(gen));
256 const SkIRect subset = SkIRect::MakeLTRB(50, 50, 100, 100);
258 gen = fFactory(ctx, fPicture);
259 fImageSubset = SkImage::MakeFromGenerator(std::move(gen), &subset);
261 SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
262 SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));
265 static void draw_as_bitmap(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
267 as_IB(image)->getROPixels(&bitmap, canvas->imageInfo().colorSpace());
268 canvas->drawBitmap(bitmap, x, y);
271 static void draw_as_tex(SkCanvas* canvas, SkImage* image, SkScalar x, SkScalar y) {
273 sk_sp<SkColorSpace> texColorSpace;
274 sk_sp<GrTextureProxy> proxy(
275 as_IB(image)->asTextureProxyRef(canvas->getGrContext(), GrSamplerParams::ClampBilerp(),
276 canvas->imageInfo().colorSpace(), &texColorSpace,
279 // show placeholder if we have no texture
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);
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(canvas->getGrContext(), image->uniqueID(),
292 kPremul_SkAlphaType, std::move(proxy),
293 std::move(texColorSpace), SkBudgeted::kNo));
294 canvas->drawImage(texImage.get(), x, y);
298 void drawSet(SkCanvas* canvas) const {
299 SkMatrix matrix = SkMatrix::MakeTrans(-100, -100);
300 canvas->drawPicture(fPicture, &matrix, nullptr);
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.
305 draw_as_tex(canvas, fImage.get(), 310, 0);
306 draw_as_tex(canvas, fImageSubset.get(), 310+101, 0);
308 draw_as_bitmap(canvas, fImage.get(), 150, 0);
309 draw_as_bitmap(canvas, fImageSubset.get(), 150+101, 0);
312 void onDraw(SkCanvas* canvas) override {
313 this->makeCaches(canvas->getGrContext());
315 canvas->translate(20, 20);
317 this->drawSet(canvas);
320 canvas->translate(0, 130);
321 canvas->scale(0.25f, 0.25f);
322 this->drawSet(canvas);
326 canvas->translate(0, 200);
328 this->drawSet(canvas);
333 typedef skiagm::GM INHERITED;
335 DEF_GM( return new ImageCacheratorGM("picture", make_pic_generator); )
336 DEF_GM( return new ImageCacheratorGM("raster", make_ras_generator); )
338 DEF_GM( return new ImageCacheratorGM("texture", make_tex_generator); )