Plumb dst color space in many places, rather than "mode"
[platform/upstream/libSkiaSharp.git] / src / core / SkSpecialImage.cpp
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 "SkSpecialImage.h"
9 #include "SkBitmap.h"
10 #include "SkImage.h"
11 #include "SkBitmapCache.h"
12 #include "SkCanvas.h"
13 #include "SkImage_Base.h"
14 #include "SkSpecialSurface.h"
15 #include "SkSurfacePriv.h"
16 #include "SkPixelRef.h"
17
18 #if SK_SUPPORT_GPU
19 #include "GrContext.h"
20 #include "GrTexture.h"
21 #include "GrSamplerParams.h"
22 #include "GrTextureProxy.h"
23 #include "SkGr.h"
24 #include "SkGrPriv.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.
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:
37     SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps* props)
38         : INHERITED(subset, uniqueID, props) {
39     }
40     ~SkSpecialImage_Base() override { }
41
42     virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
43
44     virtual bool onGetROPixels(SkBitmap*) const = 0;
45
46     virtual GrContext* onGetContext() const { return nullptr; }
47
48     virtual SkColorSpace* onGetColorSpace() const = 0;
49
50 #if SK_SUPPORT_GPU
51     virtual sk_sp<GrTexture> onAsTextureRef(GrContext* context) const = 0;
52     virtual sk_sp<GrTextureProxy> onAsTextureProxy(GrContext* context) const = 0;
53 #endif
54
55     virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
56
57     virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
58                                                   const SkISize& size, SkAlphaType at) const = 0;
59
60     virtual sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const = 0;
61
62     virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
63                                                 const SkISize& size, SkAlphaType at) const = 0;
64
65 private:
66     typedef SkSpecialImage INHERITED;
67 };
68
69 ///////////////////////////////////////////////////////////////////////////////
70 static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) {
71     return static_cast<const SkSpecialImage_Base*>(image);
72 }
73
74 SkSpecialImage::SkSpecialImage(const SkIRect& subset,
75                                uint32_t uniqueID,
76                                const SkSurfaceProps* props)
77     : fProps(SkSurfacePropsCopyOrDefault(props))
78     , fSubset(subset)
79     , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) {
80 }
81
82 sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrContext* context) {
83 #if SK_SUPPORT_GPU
84     if (!context) {
85         return nullptr;
86     }
87     if (GrContext* curContext = as_SIB(this)->onGetContext()) {
88         return curContext == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
89     }
90
91     SkBitmap bmp;
92     // At this point, we are definitely not texture-backed, so we must be raster or generator
93     // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that
94     // we are strictly raster-backed (i.e. generator images become raster when they are specialized)
95     // in which case getROPixels could turn into peekPixels...
96     if (!this->getROPixels(&bmp)) {
97         return nullptr;
98     }
99
100     if (bmp.empty()) {
101         return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props());
102     }
103
104     sk_sp<GrTexture> resultTex(
105         GrRefCachedBitmapTexture(context, bmp, GrSamplerParams::ClampNoFilter()));
106     if (!resultTex) {
107         return nullptr;
108     }
109
110     return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(resultTex->width(), resultTex->height()),
111                                        this->uniqueID(),
112                                        resultTex, sk_ref_sp(this->getColorSpace()), &this->props(),
113                                        this->alphaType());
114 #else
115     return nullptr;
116 #endif
117 }
118
119 void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const {
120     return as_SIB(this)->onDraw(canvas, x, y, paint);
121 }
122
123 bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
124     return as_SIB(this)->onGetROPixels(bm);
125 }
126
127 bool SkSpecialImage::isTextureBacked() const {
128     return SkToBool(as_SIB(this)->onGetContext());
129 }
130
131 GrContext* SkSpecialImage::getContext() const {
132     return as_SIB(this)->onGetContext();
133 }
134
135 SkColorSpace* SkSpecialImage::getColorSpace() const {
136     return as_SIB(this)->onGetColorSpace();
137 }
138
139 #if SK_SUPPORT_GPU
140 sk_sp<GrTexture> SkSpecialImage::asTextureRef(GrContext* context) const {
141     return as_SIB(this)->onAsTextureRef(context);
142 }
143
144 sk_sp<GrTextureProxy> SkSpecialImage::asTextureProxy(GrContext* context) const {
145     return as_SIB(this)->onAsTextureProxy(context);
146 }
147 #endif
148
149 sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageFilter::OutputProperties& outProps,
150                                                     const SkISize& size, SkAlphaType at) const {
151     return as_SIB(this)->onMakeSurface(outProps, size, at);
152 }
153
154 sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageFilter::OutputProperties& outProps,
155                                                   const SkISize& size, SkAlphaType at) const {
156     return as_SIB(this)->onMakeTightSurface(outProps, size, at);
157 }
158
159 sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
160     return as_SIB(this)->onMakeSubset(subset);
161 }
162
163 sk_sp<SkImage> SkSpecialImage::makeTightSubset(const SkIRect& subset) const {
164     return as_SIB(this)->onMakeTightSubset(subset);
165 }
166
167 #ifdef SK_DEBUG
168 static bool rect_fits(const SkIRect& rect, int width, int height) {
169     if (0 == width && 0 == height) {
170         SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom);
171         return true;
172     }
173
174     return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
175            rect.fRight >= 0 && rect.fRight <= width &&
176            rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
177            rect.fBottom >= 0 && rect.fBottom <= height;
178 }
179 #endif
180
181 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(const SkIRect& subset,
182                                                     sk_sp<SkImage> image,
183                                                     SkColorSpace* dstColorSpace,
184                                                     const SkSurfaceProps* props) {
185     SkASSERT(rect_fits(subset, image->width(), image->height()));
186
187 #if SK_SUPPORT_GPU
188     if (GrTexture* texture = as_IB(image)->peekTexture()) {
189         return MakeFromGpu(subset, image->uniqueID(), sk_ref_sp(texture),
190                            sk_ref_sp(as_IB(image)->onImageInfo().colorSpace()), props);
191     } else
192 #endif
193     {
194         SkBitmap bm;
195         if (as_IB(image)->getROPixels(&bm, dstColorSpace)) {
196             return MakeFromRaster(subset, bm, props);
197         }
198     }
199     return nullptr;
200 }
201
202 ///////////////////////////////////////////////////////////////////////////////
203
204 class SkSpecialImage_Raster : public SkSpecialImage_Base {
205 public:
206     SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps* props)
207         : INHERITED(subset, bm.getGenerationID(), props)
208         , fBitmap(bm)
209     {
210         SkASSERT(bm.pixelRef());
211
212         // We have to lock now, while bm is still in scope, since it may have come from our
213         // cache, which means we need to keep it locked until we (the special) are done, since
214         // we cannot re-generate the cache entry (if bm came from a generator).
215         fBitmap.lockPixels();
216         SkASSERT(fBitmap.getPixels());
217     }
218
219     SkAlphaType alphaType() const override { return fBitmap.alphaType(); }
220
221     size_t getSize() const override { return fBitmap.getSize(); }
222
223     void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
224         SkRect dst = SkRect::MakeXYWH(x, y,
225                                       this->subset().width(), this->subset().height());
226
227         canvas->drawBitmapRect(fBitmap, this->subset(),
228                                dst, paint, SkCanvas::kStrict_SrcRectConstraint);
229     }
230
231     bool onGetROPixels(SkBitmap* bm) const override {
232         *bm = fBitmap;
233         return true;
234     }
235
236     SkColorSpace* onGetColorSpace() const override {
237         return fBitmap.colorSpace();
238     }
239
240 #if SK_SUPPORT_GPU
241     sk_sp<GrTexture> onAsTextureRef(GrContext* context) const override {
242         if (context) {
243             return sk_ref_sp(
244                 GrRefCachedBitmapTexture(context, fBitmap, GrSamplerParams::ClampNoFilter()));
245         }
246
247         return nullptr;
248     }
249
250     sk_sp<GrTextureProxy> onAsTextureProxy(GrContext* context) const override {
251         if (context) {
252             sk_sp<GrTexture> tex(sk_ref_sp(GrRefCachedBitmapTexture(
253                 context, fBitmap, GrSamplerParams::ClampNoFilter())));
254             sk_sp<GrSurfaceProxy> sProxy = GrSurfaceProxy::MakeWrapped(std::move(tex));
255             return sk_ref_sp(sProxy->asTextureProxy());
256         }
257
258         return nullptr;
259     }
260 #endif
261
262 // TODO: The raster implementations of image filters all currently assume that the pixels are
263 // legacy N32. Until they actually check the format and operate on sRGB or F16 data appropriately,
264 // we can't enable this. (They will continue to produce incorrect results, but less-so).
265 #define RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16 0
266
267     sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
268                                           const SkISize& size, SkAlphaType at) const override {
269 #if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
270         SkColorSpace* colorSpace = outProps.colorSpace();
271 #else
272         SkColorSpace* colorSpace = nullptr;
273 #endif
274         SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
275             ? kRGBA_F16_SkColorType : kN32_SkColorType;
276         SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
277                                              sk_ref_sp(colorSpace));
278         return SkSpecialSurface::MakeRaster(info, nullptr);
279     }
280
281     sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
282         SkBitmap subsetBM;
283
284         if (!fBitmap.extractSubset(&subsetBM, subset)) {
285             return nullptr;
286         }
287
288         return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(subset.width(), subset.height()),
289                                               subsetBM,
290                                               &this->props());
291     }
292
293     sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
294         SkBitmap subsetBM;
295
296         if (!fBitmap.extractSubset(&subsetBM, subset)) {
297             return nullptr;
298         }
299
300         return SkImage::MakeFromBitmap(subsetBM);
301     }
302
303     sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
304                                         const SkISize& size, SkAlphaType at) const override {
305 #if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
306         SkColorSpace* colorSpace = outProps.colorSpace();
307 #else
308         SkColorSpace* colorSpace = nullptr;
309 #endif
310         SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
311             ? kRGBA_F16_SkColorType : kN32_SkColorType;
312         SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
313                                              sk_ref_sp(colorSpace));
314         return SkSurface::MakeRaster(info);
315     }
316
317 private:
318     SkBitmap fBitmap;
319
320     typedef SkSpecialImage_Base INHERITED;
321 };
322
323 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset,
324                                                      const SkBitmap& bm,
325                                                      const SkSurfaceProps* props) {
326     SkASSERT(rect_fits(subset, bm.width(), bm.height()));
327
328     if (!bm.pixelRef()) {
329         return nullptr;
330     }
331
332     const SkBitmap* srcBM = &bm;
333     SkBitmap tmpStorage;
334     // ImageFilters only handle N32 at the moment, so force our src to be that
335     if (!valid_for_imagefilters(bm.info())) {
336         if (!bm.copyTo(&tmpStorage, kN32_SkColorType)) {
337             return nullptr;
338         }
339         srcBM = &tmpStorage;
340     }
341     return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
342 }
343
344 #if SK_SUPPORT_GPU
345 ///////////////////////////////////////////////////////////////////////////////
346 #include "GrTexture.h"
347 #include "SkImage_Gpu.h"
348
349 class SkSpecialImage_Gpu : public SkSpecialImage_Base {
350 public:
351     SkSpecialImage_Gpu(const SkIRect& subset,
352                        uint32_t uniqueID, sk_sp<GrTexture> tex, SkAlphaType at,
353                        sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
354         : INHERITED(subset, uniqueID, props)
355         , fContext(tex->getContext())
356         , fAlphaType(at)
357         , fColorSpace(std::move(colorSpace))
358         , fAddedRasterVersionToCache(false) {
359         fSurfaceProxy = GrSurfaceProxy::MakeWrapped(std::move(tex));
360     }
361
362     SkSpecialImage_Gpu(GrContext* context, const SkIRect& subset,
363                        uint32_t uniqueID, sk_sp<GrSurfaceProxy> proxy, SkAlphaType at,
364                        sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
365         : INHERITED(subset, uniqueID, props)
366         , fContext(context)
367         , fSurfaceProxy(std::move(proxy))
368         , fAlphaType(at)
369         , fColorSpace(std::move(colorSpace))
370         , fAddedRasterVersionToCache(false) {
371     }
372
373     ~SkSpecialImage_Gpu() override {
374         if (fAddedRasterVersionToCache.load()) {
375             SkNotifyBitmapGenIDIsStale(this->uniqueID());
376         }
377     }
378
379     SkAlphaType alphaType() const override { return fAlphaType; }
380
381     size_t getSize() const override { return fSurfaceProxy->gpuMemorySize(); }
382
383     void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
384         SkRect dst = SkRect::MakeXYWH(x, y,
385                                       this->subset().width(), this->subset().height());
386
387         // TODO: add GrTextureProxy-backed SkImage_Gpus
388         GrSurface* surf = fSurfaceProxy->instantiate(fContext->textureProvider());
389         if (!surf) {
390             return;
391         }
392
393         // TODO: In this instance we know we're going to draw a sub-portion of the backing
394         // texture into the canvas so it is okay to wrap it in an SkImage. This poses
395         // some problems for full deferral however in that when the deferred SkImage_Gpu
396         // instantiates itself it is going to have to either be okay with having a larger
397         // than expected backing texture (unlikely) or the 'fit' of the SurfaceProxy needs 
398         // to be tightened (if it is deferred).
399         auto img = sk_sp<SkImage>(new SkImage_Gpu(surf->width(), surf->height(),
400                                                   this->uniqueID(), fAlphaType,
401                                                   sk_ref_sp(surf->asTexture()),
402                                                   fColorSpace, SkBudgeted::kNo));
403
404         canvas->drawImageRect(img, this->subset(),
405                               dst, paint, SkCanvas::kStrict_SrcRectConstraint);
406     }
407
408     GrContext* onGetContext() const override { return fContext; }
409
410     // This entry point should go away in favor of asTextureProxy
411     sk_sp<GrTexture> onAsTextureRef(GrContext* context) const override {
412         GrSurface* surf = fSurfaceProxy->instantiate(context->textureProvider());
413         if (!surf) {
414             return nullptr;
415         }
416         return sk_ref_sp(surf->asTexture());
417     }
418
419     sk_sp<GrTextureProxy> onAsTextureProxy(GrContext*) const override {
420         return sk_ref_sp(fSurfaceProxy->asTextureProxy());
421     }
422
423     bool onGetROPixels(SkBitmap* dst) const override {
424         if (SkBitmapCache::Find(this->uniqueID(), dst)) {
425             SkASSERT(dst->getGenerationID() == this->uniqueID());
426             SkASSERT(dst->isImmutable());
427             SkASSERT(dst->getPixels());
428             return true;
429         }
430
431         SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
432                                                 this->alphaType(), fColorSpace);
433
434         if (!dst->tryAllocPixels(info)) {
435             return false;
436         }
437
438         // Reading back to an SkBitmap ends deferral
439         GrSurface* surface = fSurfaceProxy->instantiate(fContext->textureProvider());
440         if (!surface) {
441             return false;
442         }
443
444         if (!surface->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
445                                  dst->getPixels(), dst->rowBytes())) {
446             return false;
447         }
448
449         dst->pixelRef()->setImmutableWithID(this->uniqueID());
450         SkBitmapCache::Add(this->uniqueID(), *dst);
451         fAddedRasterVersionToCache.store(true);
452         return true;
453     }
454
455     SkColorSpace* onGetColorSpace() const override {
456         return fColorSpace.get();
457     }
458
459     sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
460                                           const SkISize& size, SkAlphaType at) const override {
461         if (!fContext) {
462             return nullptr;
463         }
464
465         SkColorSpace* colorSpace = outProps.colorSpace();
466         return SkSpecialSurface::MakeRenderTarget(
467             fContext, size.width(), size.height(),
468             GrRenderableConfigForColorSpace(colorSpace), sk_ref_sp(colorSpace));
469     }
470
471     sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
472         return SkSpecialImage::MakeDeferredFromGpu(fContext,
473                                                    subset,
474                                                    this->uniqueID(),
475                                                    fSurfaceProxy,
476                                                    fColorSpace,
477                                                    &this->props(),
478                                                    fAlphaType);
479     }
480
481     sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
482         // TODO: add GrTextureProxy-backed SkImage_Gpus
483         GrSurface* surf = fSurfaceProxy->instantiate(fContext->textureProvider());
484         if (!surf) {
485             return nullptr;
486         }
487
488         if (0 == subset.fLeft && 0 == subset.fTop &&
489             fSurfaceProxy->width() == subset.width() &&
490             fSurfaceProxy->height() == subset.height()) {
491             // The existing GrTexture is already tight so reuse it in the SkImage
492             return sk_make_sp<SkImage_Gpu>(surf->width(), surf->height(),
493                                            kNeedNewImageUniqueID, fAlphaType,
494                                            sk_ref_sp(surf->asTexture()),
495                                            fColorSpace, SkBudgeted::kYes);
496         }
497
498         GrSurfaceDesc desc = fSurfaceProxy->desc();
499         desc.fWidth = subset.width();
500         desc.fHeight = subset.height();
501
502         sk_sp<GrTexture> subTx(fContext->textureProvider()->createTexture(desc, SkBudgeted::kYes));
503         if (!subTx) {
504             return nullptr;
505         }
506         fContext->copySurface(subTx.get(), surf, subset, SkIPoint::Make(0, 0));
507         return sk_make_sp<SkImage_Gpu>(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID,
508                                        fAlphaType, std::move(subTx), fColorSpace, SkBudgeted::kYes);
509     }
510
511     sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
512                                         const SkISize& size, SkAlphaType at) const override {
513         SkColorSpace* colorSpace = outProps.colorSpace();
514         SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
515             ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType;
516         SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
517                                              sk_ref_sp(colorSpace));
518         return SkSurface::MakeRenderTarget(fContext, SkBudgeted::kYes, info);
519     }
520
521 private:
522     GrContext*              fContext;
523     sk_sp<GrSurfaceProxy>   fSurfaceProxy;
524     const SkAlphaType       fAlphaType;
525     sk_sp<SkColorSpace>     fColorSpace;
526     mutable SkAtomic<bool>  fAddedRasterVersionToCache;
527
528     typedef SkSpecialImage_Base INHERITED;
529 };
530
531 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromGpu(const SkIRect& subset,
532                                                   uint32_t uniqueID,
533                                                   sk_sp<GrTexture> tex,
534                                                   sk_sp<SkColorSpace> colorSpace,
535                                                   const SkSurfaceProps* props,
536                                                   SkAlphaType at) {
537     SkASSERT(rect_fits(subset, tex->width(), tex->height()));
538     return sk_make_sp<SkSpecialImage_Gpu>(subset, uniqueID, std::move(tex), at,
539                                           std::move(colorSpace), props);
540 }
541
542 sk_sp<SkSpecialImage> SkSpecialImage::MakeDeferredFromGpu(GrContext* context,
543                                                           const SkIRect& subset,
544                                                           uint32_t uniqueID,
545                                                           sk_sp<GrSurfaceProxy> proxy,
546                                                           sk_sp<SkColorSpace> colorSpace,
547                                                           const SkSurfaceProps* props,
548                                                           SkAlphaType at) {
549     SkASSERT(rect_fits(subset, proxy->width(), proxy->height()));
550     return sk_make_sp<SkSpecialImage_Gpu>(context, subset, uniqueID, std::move(proxy), at,
551                                           std::move(colorSpace), props);
552 }
553 #endif