• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 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 "src/core/SkSpecialImage.h"
9 
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkImage.h"
13 #include "src/core/SkSpecialSurface.h"
14 #include "src/core/SkSurfacePriv.h"
15 #include "src/image/SkImage_Base.h"
16 
17 #if SK_SUPPORT_GPU
18 #include "include/gpu/GrDirectContext.h"
19 #include "include/gpu/GrRecordingContext.h"
20 #include "src/gpu/GrImageInfo.h"
21 #include "src/gpu/GrProxyProvider.h"
22 #include "src/gpu/GrRecordingContextPriv.h"
23 #include "src/gpu/GrTextureProxy.h"
24 #include "src/image/SkImage_Gpu.h"
25 #endif
26 
27 // Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
28 // a given info is supported.
valid_for_imagefilters(const SkImageInfo & info)29 static bool valid_for_imagefilters(const SkImageInfo& info) {
30     // no support for other swizzles/depths yet
31     return info.colorType() == kN32_SkColorType;
32 }
33 
34 ///////////////////////////////////////////////////////////////////////////////
35 class SkSpecialImage_Base : public SkSpecialImage {
36 public:
SkSpecialImage_Base(const SkIRect & subset,uint32_t uniqueID,const SkSurfaceProps & props)37     SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps& props)
38         : INHERITED(subset, uniqueID, props) {
39     }
~SkSpecialImage_Base()40     ~SkSpecialImage_Base() override { }
41 
42     virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkSamplingOptions&,
43                         const SkPaint*) const = 0;
44 
45     virtual bool onGetROPixels(SkBitmap*) const = 0;
46 
onGetContext() const47     virtual GrRecordingContext* onGetContext() const { return nullptr; }
48 
49     virtual SkColorSpace* onGetColorSpace() const = 0;
50 
51 #if SK_SUPPORT_GPU
52     virtual GrSurfaceProxyView onView(GrRecordingContext* context) const = 0;
53 #endif
54 
55     // This subset is relative to the backing store's coordinate frame, it has already been mapped
56     // from the content rect by the non-virtual makeSubset().
57     virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
58 
59     virtual sk_sp<SkSpecialSurface> onMakeSurface(
60             SkColorType colorType, const SkColorSpace* colorSpace, const SkISize& size,
61             SkAlphaType at, const SkSurfaceProps&) const = 0;
62 
63     // This subset (when not null) is relative to the backing store's coordinate frame, it has
64     // already been mapped from the content rect by the non-virtual asImage().
65     virtual sk_sp<SkImage> onAsImage(const SkIRect* subset) const = 0;
66 
67     virtual sk_sp<SkSurface> onMakeTightSurface(
68             SkColorType colorType, const SkColorSpace* colorSpace,
69             const SkISize& size, SkAlphaType at) const = 0;
70 
71 private:
72     using INHERITED = SkSpecialImage;
73 };
74 
75 ///////////////////////////////////////////////////////////////////////////////
as_SIB(const SkSpecialImage * image)76 static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) {
77     return static_cast<const SkSpecialImage_Base*>(image);
78 }
79 
SkSpecialImage(const SkIRect & subset,uint32_t uniqueID,const SkSurfaceProps & props)80 SkSpecialImage::SkSpecialImage(const SkIRect& subset,
81                                uint32_t uniqueID,
82                                const SkSurfaceProps& props)
83     : fProps(props)
84     , fSubset(subset)
85     , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) {
86 }
87 
draw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint) const88 void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
89                           const SkSamplingOptions& sampling, const SkPaint* paint) const {
90     return as_SIB(this)->onDraw(canvas, x, y, sampling, paint);
91 }
92 
getROPixels(SkBitmap * bm) const93 bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
94     return as_SIB(this)->onGetROPixels(bm);
95 }
96 
isTextureBacked() const97 bool SkSpecialImage::isTextureBacked() const {
98     return SkToBool(as_SIB(this)->onGetContext());
99 }
100 
getContext() const101 GrRecordingContext* SkSpecialImage::getContext() const {
102     return as_SIB(this)->onGetContext();
103 }
104 
getColorSpace() const105 SkColorSpace* SkSpecialImage::getColorSpace() const {
106     return as_SIB(this)->onGetColorSpace();
107 }
108 
109 #if SK_SUPPORT_GPU
view(GrRecordingContext * context) const110 GrSurfaceProxyView SkSpecialImage::view(GrRecordingContext* context) const {
111     return as_SIB(this)->onView(context);
112 }
113 #endif
114 
makeSurface(SkColorType colorType,const SkColorSpace * colorSpace,const SkISize & size,SkAlphaType at,const SkSurfaceProps & props) const115 sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(
116         SkColorType colorType, const SkColorSpace* colorSpace, const SkISize& size,
117         SkAlphaType at, const SkSurfaceProps& props) const {
118     return as_SIB(this)->onMakeSurface(colorType, colorSpace, size, at, props);
119 }
120 
makeTightSurface(SkColorType colorType,const SkColorSpace * colorSpace,const SkISize & size,SkAlphaType at) const121 sk_sp<SkSurface> SkSpecialImage::makeTightSurface(
122         SkColorType colorType, const SkColorSpace* colorSpace, const SkISize& size,
123         SkAlphaType at) const {
124     return as_SIB(this)->onMakeTightSurface(colorType, colorSpace, size, at);
125 }
126 
makeSubset(const SkIRect & subset) const127 sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
128     SkIRect absolute = subset.makeOffset(this->subset().topLeft());
129     return as_SIB(this)->onMakeSubset(absolute);
130 }
131 
asImage(const SkIRect * subset) const132 sk_sp<SkImage> SkSpecialImage::asImage(const SkIRect* subset) const {
133     if (subset) {
134         SkIRect absolute = subset->makeOffset(this->subset().topLeft());
135         return as_SIB(this)->onAsImage(&absolute);
136     } else {
137         return as_SIB(this)->onAsImage(nullptr);
138     }
139 }
140 
141 #if defined(SK_DEBUG) || SK_SUPPORT_GPU
rect_fits(const SkIRect & rect,int width,int height)142 static bool rect_fits(const SkIRect& rect, int width, int height) {
143     if (0 == width && 0 == height) {
144         SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom);
145         return true;
146     }
147 
148     return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
149            rect.fRight >= 0 && rect.fRight <= width &&
150            rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
151            rect.fBottom >= 0 && rect.fBottom <= height;
152 }
153 #endif
154 
MakeFromImage(GrRecordingContext * rContext,const SkIRect & subset,sk_sp<SkImage> image,const SkSurfaceProps & props)155 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(GrRecordingContext* rContext,
156                                                     const SkIRect& subset,
157                                                     sk_sp<SkImage> image,
158                                                     const SkSurfaceProps& props) {
159     SkASSERT(rect_fits(subset, image->width(), image->height()));
160 
161 #if SK_SUPPORT_GPU
162     if (rContext) {
163         auto [view, ct] = as_IB(image)->asView(rContext, GrMipmapped::kNo);
164         return MakeDeferredFromGpu(rContext,
165                                    subset,
166                                    image->uniqueID(),
167                                    std::move(view),
168                                    ct,
169                                    image->refColorSpace(),
170                                    props);
171     }
172 #endif
173 
174     // raster to gpu is supported here, but gpu to raster is not
175     SkBitmap bm;
176     if (as_IB(image)->getROPixels(nullptr, &bm)) {
177         return MakeFromRaster(subset, bm, props);
178     }
179     return nullptr;
180 }
181 
182 ///////////////////////////////////////////////////////////////////////////////
183 
184 class SkSpecialImage_Raster : public SkSpecialImage_Base {
185 public:
SkSpecialImage_Raster(const SkIRect & subset,const SkBitmap & bm,const SkSurfaceProps & props)186     SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps& props)
187         : INHERITED(subset, bm.getGenerationID(), props)
188         , fBitmap(bm)
189     {
190         SkASSERT(bm.pixelRef());
191         SkASSERT(fBitmap.getPixels());
192     }
193 
alphaType() const194     SkAlphaType alphaType() const override { return fBitmap.alphaType(); }
195 
colorType() const196     SkColorType colorType() const override { return fBitmap.colorType(); }
197 
getSize() const198     size_t getSize() const override { return fBitmap.computeByteSize(); }
199 
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint) const200     void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkSamplingOptions& sampling,
201                 const SkPaint* paint) const override {
202         SkRect dst = SkRect::MakeXYWH(x, y,
203                                       this->subset().width(), this->subset().height());
204 
205         canvas->drawImageRect(fBitmap.asImage(), SkRect::Make(this->subset()), dst,
206                               sampling, paint, SkCanvas::kStrict_SrcRectConstraint);
207     }
208 
onGetROPixels(SkBitmap * bm) const209     bool onGetROPixels(SkBitmap* bm) const override {
210         return fBitmap.extractSubset(bm, this->subset());
211     }
212 
onGetColorSpace() const213     SkColorSpace* onGetColorSpace() const override {
214         return fBitmap.colorSpace();
215     }
216 
217 #if SK_SUPPORT_GPU
onView(GrRecordingContext * context) const218     GrSurfaceProxyView onView(GrRecordingContext* context) const override {
219         if (context) {
220             return std::get<0>(GrMakeCachedBitmapProxyView(context, fBitmap, GrMipmapped::kNo));
221         }
222 
223         return {};
224     }
225 #endif
226 
onMakeSurface(SkColorType colorType,const SkColorSpace * colorSpace,const SkISize & size,SkAlphaType at,const SkSurfaceProps & props) const227     sk_sp<SkSpecialSurface> onMakeSurface(SkColorType colorType, const SkColorSpace* colorSpace,
228                                           const SkISize& size, SkAlphaType at,
229                                           const SkSurfaceProps& props) const override {
230         // Ignore the requested color type, the raster backend currently only supports N32
231         colorType = kN32_SkColorType;   // TODO: find ways to allow f16
232         SkImageInfo info = SkImageInfo::Make(size, colorType, at, sk_ref_sp(colorSpace));
233         return SkSpecialSurface::MakeRaster(info, props);
234     }
235 
onMakeSubset(const SkIRect & subset) const236     sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
237         // No need to extract subset, onGetROPixels handles that when needed
238         return SkSpecialImage::MakeFromRaster(subset, fBitmap, this->props());
239     }
240 
onAsImage(const SkIRect * subset) const241     sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
242         if (subset) {
243             SkBitmap subsetBM;
244 
245             if (!fBitmap.extractSubset(&subsetBM, *subset)) {
246                 return nullptr;
247             }
248 
249             return subsetBM.asImage();
250         }
251 
252         return fBitmap.asImage();
253     }
254 
onMakeTightSurface(SkColorType colorType,const SkColorSpace * colorSpace,const SkISize & size,SkAlphaType at) const255 sk_sp<SkSurface> onMakeTightSurface(SkColorType colorType, const SkColorSpace* colorSpace,
256                                         const SkISize& size, SkAlphaType at) const override {
257         // Ignore the requested color type, the raster backend currently only supports N32
258         colorType = kN32_SkColorType;   // TODO: find ways to allow f16
259         SkImageInfo info = SkImageInfo::Make(size, colorType, at, sk_ref_sp(colorSpace));
260         return SkSurface::MakeRaster(info);
261     }
262 
263 private:
264     SkBitmap fBitmap;
265 
266     using INHERITED = SkSpecialImage_Base;
267 };
268 
MakeFromRaster(const SkIRect & subset,const SkBitmap & bm,const SkSurfaceProps & props)269 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset,
270                                                      const SkBitmap& bm,
271                                                      const SkSurfaceProps& props) {
272     SkASSERT(rect_fits(subset, bm.width(), bm.height()));
273 
274     if (!bm.pixelRef()) {
275         return nullptr;
276     }
277 
278     const SkBitmap* srcBM = &bm;
279     SkBitmap tmp;
280     // ImageFilters only handle N32 at the moment, so force our src to be that
281     if (!valid_for_imagefilters(bm.info())) {
282         if (!tmp.tryAllocPixels(bm.info().makeColorType(kN32_SkColorType)) ||
283             !bm.readPixels(tmp.info(), tmp.getPixels(), tmp.rowBytes(), 0, 0))
284         {
285             return nullptr;
286         }
287         srcBM = &tmp;
288     }
289     return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
290 }
291 
CopyFromRaster(const SkIRect & subset,const SkBitmap & bm,const SkSurfaceProps & props)292 sk_sp<SkSpecialImage> SkSpecialImage::CopyFromRaster(const SkIRect& subset,
293                                                      const SkBitmap& bm,
294                                                      const SkSurfaceProps& props) {
295     SkASSERT(rect_fits(subset, bm.width(), bm.height()));
296 
297     if (!bm.pixelRef()) {
298         return nullptr;
299     }
300 
301     SkBitmap tmp;
302     SkImageInfo info = bm.info().makeDimensions(subset.size());
303     // As in MakeFromRaster, must force src to N32 for ImageFilters
304     if (!valid_for_imagefilters(bm.info())) {
305         info = info.makeColorType(kN32_SkColorType);
306     }
307     if (!tmp.tryAllocPixels(info)) {
308         return nullptr;
309     }
310     if (!bm.readPixels(tmp.info(), tmp.getPixels(), tmp.rowBytes(), subset.x(), subset.y())) {
311         return nullptr;
312     }
313 
314     // Since we're making a copy of the raster, the resulting special image is the exact size
315     // of the requested subset of the original and no longer needs to be offset by subset's left
316     // and top, since those were relative to the original's buffer.
317     return sk_make_sp<SkSpecialImage_Raster>(
318             SkIRect::MakeWH(subset.width(), subset.height()), tmp, props);
319 }
320 
321 #if SK_SUPPORT_GPU
322 ///////////////////////////////////////////////////////////////////////////////
wrap_proxy_in_image(GrRecordingContext * context,GrSurfaceProxyView view,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace)323 static sk_sp<SkImage> wrap_proxy_in_image(GrRecordingContext* context, GrSurfaceProxyView view,
324                                           SkColorType colorType, SkAlphaType alphaType,
325                                           sk_sp<SkColorSpace> colorSpace) {
326     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context),
327                                    kNeedNewImageUniqueID,
328                                    std::move(view),
329                                    SkColorInfo(colorType, alphaType, std::move(colorSpace)));
330 }
331 
332 class SkSpecialImage_Gpu : public SkSpecialImage_Base {
333 public:
SkSpecialImage_Gpu(GrRecordingContext * context,const SkIRect & subset,uint32_t uniqueID,GrSurfaceProxyView view,GrColorType ct,SkAlphaType at,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps & props)334     SkSpecialImage_Gpu(GrRecordingContext* context, const SkIRect& subset,
335                        uint32_t uniqueID, GrSurfaceProxyView view, GrColorType ct,
336                        SkAlphaType at, sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps& props)
337         : INHERITED(subset, uniqueID, props)
338         , fContext(context)
339         , fView(std::move(view))
340         , fColorType(ct)
341         , fAlphaType(at)
342         , fColorSpace(std::move(colorSpace)) {
343     }
344 
alphaType() const345     SkAlphaType alphaType() const override { return fAlphaType; }
346 
colorType() const347     SkColorType colorType() const override { return GrColorTypeToSkColorType(fColorType); }
348 
getSize() const349     size_t getSize() const override {
350         return fView.proxy()->gpuMemorySize();
351     }
352 
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint) const353     void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkSamplingOptions& sampling,
354                 const SkPaint* paint) const override {
355         SkRect dst = SkRect::MakeXYWH(x, y,
356                                       this->subset().width(), this->subset().height());
357 
358         // TODO: In this instance we know we're going to draw a sub-portion of the backing
359         // texture into the canvas so it is okay to wrap it in an SkImage. This poses
360         // some problems for full deferral however in that when the deferred SkImage_Gpu
361         // instantiates itself it is going to have to either be okay with having a larger
362         // than expected backing texture (unlikely) or the 'fit' of the SurfaceProxy needs
363         // to be tightened (if it is deferred).
364         sk_sp<SkImage> img = sk_sp<SkImage>(
365                 new SkImage_Gpu(sk_ref_sp(canvas->recordingContext()),
366                                 this->uniqueID(),
367                                 fView,
368                                 SkColorInfo(this->colorType(), fAlphaType, fColorSpace)));
369 
370         canvas->drawImageRect(img, SkRect::Make(this->subset()), dst,
371                               sampling, paint, SkCanvas::kStrict_SrcRectConstraint);
372     }
373 
onGetContext() const374     GrRecordingContext* onGetContext() const override { return fContext; }
375 
onView(GrRecordingContext * context) const376     GrSurfaceProxyView onView(GrRecordingContext* context) const override { return fView; }
377 
onGetROPixels(SkBitmap * dst) const378     bool onGetROPixels(SkBitmap* dst) const override {
379         // This should never be called: All GPU image filters are implemented entirely on the GPU,
380         // so we never perform read-back.
381         SkASSERT(false);
382         return false;
383     }
384 
onGetColorSpace() const385     SkColorSpace* onGetColorSpace() const override {
386         return fColorSpace.get();
387     }
388 
onMakeSurface(SkColorType colorType,const SkColorSpace * colorSpace,const SkISize & size,SkAlphaType at,const SkSurfaceProps & props) const389     sk_sp<SkSpecialSurface> onMakeSurface(SkColorType colorType, const SkColorSpace* colorSpace,
390                                           const SkISize& size, SkAlphaType at,
391                                           const SkSurfaceProps& props) const override {
392         if (!fContext) {
393             return nullptr;
394         }
395 
396         SkImageInfo ii = SkImageInfo::Make(size, colorType, at, sk_ref_sp(colorSpace));
397 
398         return SkSpecialSurface::MakeRenderTarget(fContext, ii, props);
399     }
400 
onMakeSubset(const SkIRect & subset) const401     sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
402         return SkSpecialImage::MakeDeferredFromGpu(fContext,
403                                                    subset,
404                                                    this->uniqueID(),
405                                                    fView,
406                                                    fColorType,
407                                                    fColorSpace,
408                                                    this->props(),
409                                                    fAlphaType);
410     }
411 
onAsImage(const SkIRect * subset) const412     sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
413         GrSurfaceProxy* proxy = fView.proxy();
414         if (subset) {
415             if (proxy->isFunctionallyExact() && *subset == SkIRect::MakeSize(proxy->dimensions())) {
416                 proxy->priv().exactify(false);
417                 // The existing GrTexture is already tight so reuse it in the SkImage
418                 return wrap_proxy_in_image(fContext, fView, this->colorType(), fAlphaType,
419                                            fColorSpace);
420             }
421 
422             auto subsetView = GrSurfaceProxyView::Copy(fContext, fView, GrMipmapped::kNo, *subset,
423                                                        SkBackingFit::kExact, SkBudgeted::kYes);
424             if (!subsetView) {
425                 return nullptr;
426             }
427             SkASSERT(subsetView.asTextureProxy());
428             SkASSERT(subsetView.proxy()->priv().isExact());
429 
430             // MDB: this is acceptable (wrapping subsetProxy in an SkImage) bc Copy will
431             // return a kExact-backed proxy
432             return wrap_proxy_in_image(fContext, std::move(subsetView), this->colorType(),
433                                        fAlphaType, fColorSpace);
434         }
435 
436         proxy->priv().exactify(true);
437 
438         return wrap_proxy_in_image(fContext, fView, this->colorType(), fAlphaType, fColorSpace);
439     }
440 
onMakeTightSurface(SkColorType colorType,const SkColorSpace * colorSpace,const SkISize & size,SkAlphaType at) const441     sk_sp<SkSurface> onMakeTightSurface(SkColorType colorType, const SkColorSpace* colorSpace,
442                                         const SkISize& size, SkAlphaType at) const override {
443         // TODO (michaelludwig): Why does this ignore colorType but onMakeSurface doesn't ignore it?
444         //    Once makeTightSurface() goes away, should this type overriding behavior be moved into
445         //    onMakeSurface() or is this unnecessary?
446         colorType = colorSpace && colorSpace->gammaIsLinear()
447             ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType;
448         SkImageInfo info = SkImageInfo::Make(size, colorType, at, sk_ref_sp(colorSpace));
449         return SkSurface::MakeRenderTarget(fContext, SkBudgeted::kYes, info);
450     }
451 
452 private:
453     GrRecordingContext*       fContext;
454     GrSurfaceProxyView        fView;
455     const GrColorType         fColorType;
456     const SkAlphaType         fAlphaType;
457     sk_sp<SkColorSpace>       fColorSpace;
458 
459     using INHERITED = SkSpecialImage_Base;
460 };
461 
MakeDeferredFromGpu(GrRecordingContext * context,const SkIRect & subset,uint32_t uniqueID,GrSurfaceProxyView view,GrColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps & props,SkAlphaType at)462 sk_sp<SkSpecialImage> SkSpecialImage::MakeDeferredFromGpu(GrRecordingContext* context,
463                                                           const SkIRect& subset,
464                                                           uint32_t uniqueID,
465                                                           GrSurfaceProxyView view,
466                                                           GrColorType colorType,
467                                                           sk_sp<SkColorSpace> colorSpace,
468                                                           const SkSurfaceProps& props,
469                                                           SkAlphaType at) {
470     if (!context || context->abandoned() || !view.asTextureProxy()) {
471         return nullptr;
472     }
473     SkASSERT_RELEASE(rect_fits(subset, view.proxy()->width(), view.proxy()->height()));
474     return sk_make_sp<SkSpecialImage_Gpu>(context, subset, uniqueID, std::move(view), colorType,
475                                           at, std::move(colorSpace), props);
476 }
477 #endif
478