Home | History | Annotate | Download | only in core
      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 "GrContextPriv.h"
     21 #include "GrProxyProvider.h"
     22 #include "GrSurfaceContext.h"
     23 #include "GrTextureProxy.h"
     24 #include "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.
     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<GrTextureProxy> onAsTextureProxyRef(GrContext* context) const = 0;
     52 #endif
     53 
     54     virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0;
     55 
     56     virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
     57                                                   const SkISize& size, SkAlphaType at) const = 0;
     58 
     59     virtual sk_sp<SkImage> onAsImage(const SkIRect* subset) const = 0;
     60 
     61     virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
     62                                                 const SkISize& size, SkAlphaType at) const = 0;
     63 
     64 private:
     65     typedef SkSpecialImage INHERITED;
     66 };
     67 
     68 ///////////////////////////////////////////////////////////////////////////////
     69 static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) {
     70     return static_cast<const SkSpecialImage_Base*>(image);
     71 }
     72 
     73 SkSpecialImage::SkSpecialImage(const SkIRect& subset,
     74                                uint32_t uniqueID,
     75                                const SkSurfaceProps* props)
     76     : fProps(SkSurfacePropsCopyOrDefault(props))
     77     , fSubset(subset)
     78     , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) {
     79 }
     80 
     81 sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrContext* context) {
     82 #if SK_SUPPORT_GPU
     83     if (!context) {
     84         return nullptr;
     85     }
     86     if (GrContext* curContext = as_SIB(this)->onGetContext()) {
     87         return curContext == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr;
     88     }
     89 
     90     auto proxyProvider = context->contextPriv().proxyProvider();
     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     // TODO: this is a tight copy of 'bmp' but it doesn't have to be (given SkSpecialImage's
    105     // semantics). Since this is cached though we would have to bake the fit into the cache key.
    106     sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(proxyProvider, bmp);
    107     if (!proxy) {
    108         return nullptr;
    109     }
    110 
    111     const SkIRect rect = SkIRect::MakeWH(proxy->width(), proxy->height());
    112 
    113     // GrMakeCachedBitmapProxy has uploaded only the specified subset of 'bmp' so we need not
    114     // bother with SkBitmap::getSubset
    115     return SkSpecialImage::MakeDeferredFromGpu(context,
    116                                                rect,
    117                                                this->uniqueID(),
    118                                                std::move(proxy),
    119                                                sk_ref_sp(this->getColorSpace()),
    120                                                &this->props(),
    121                                                this->alphaType());
    122 #else
    123     return nullptr;
    124 #endif
    125 }
    126 
    127 void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const {
    128     return as_SIB(this)->onDraw(canvas, x, y, paint);
    129 }
    130 
    131 bool SkSpecialImage::getROPixels(SkBitmap* bm) const {
    132     return as_SIB(this)->onGetROPixels(bm);
    133 }
    134 
    135 bool SkSpecialImage::isTextureBacked() const {
    136     return SkToBool(as_SIB(this)->onGetContext());
    137 }
    138 
    139 GrContext* SkSpecialImage::getContext() const {
    140     return as_SIB(this)->onGetContext();
    141 }
    142 
    143 SkColorSpace* SkSpecialImage::getColorSpace() const {
    144     return as_SIB(this)->onGetColorSpace();
    145 }
    146 
    147 #if SK_SUPPORT_GPU
    148 sk_sp<GrTextureProxy> SkSpecialImage::asTextureProxyRef(GrContext* context) const {
    149     return as_SIB(this)->onAsTextureProxyRef(context);
    150 }
    151 #endif
    152 
    153 sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageFilter::OutputProperties& outProps,
    154                                                     const SkISize& size, SkAlphaType at) const {
    155     return as_SIB(this)->onMakeSurface(outProps, size, at);
    156 }
    157 
    158 sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageFilter::OutputProperties& outProps,
    159                                                   const SkISize& size, SkAlphaType at) const {
    160     return as_SIB(this)->onMakeTightSurface(outProps, size, at);
    161 }
    162 
    163 sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const {
    164     return as_SIB(this)->onMakeSubset(subset);
    165 }
    166 
    167 sk_sp<SkImage> SkSpecialImage::asImage(const SkIRect* subset) const {
    168     return as_SIB(this)->onAsImage(subset);
    169 }
    170 
    171 
    172 #ifdef SK_DEBUG
    173 static bool rect_fits(const SkIRect& rect, int width, int height) {
    174     if (0 == width && 0 == height) {
    175         SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom);
    176         return true;
    177     }
    178 
    179     return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
    180            rect.fRight >= 0 && rect.fRight <= width &&
    181            rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
    182            rect.fBottom >= 0 && rect.fBottom <= height;
    183 }
    184 #endif
    185 
    186 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(const SkIRect& subset,
    187                                                     sk_sp<SkImage> image,
    188                                                     SkColorSpace* dstColorSpace,
    189                                                     const SkSurfaceProps* props) {
    190     SkASSERT(rect_fits(subset, image->width(), image->height()));
    191 
    192 #if SK_SUPPORT_GPU
    193     if (sk_sp<GrTextureProxy> proxy = as_IB(image)->asTextureProxyRef()) {
    194         GrContext* context = ((SkImage_Gpu*) as_IB(image))->context();
    195 
    196         return MakeDeferredFromGpu(context, subset, image->uniqueID(), std::move(proxy),
    197                                    as_IB(image)->onImageInfo().refColorSpace(), props);
    198     } else
    199 #endif
    200     {
    201         SkBitmap bm;
    202         if (as_IB(image)->getROPixels(&bm, dstColorSpace)) {
    203             return MakeFromRaster(subset, bm, props);
    204         }
    205     }
    206     return nullptr;
    207 }
    208 
    209 ///////////////////////////////////////////////////////////////////////////////
    210 
    211 class SkSpecialImage_Raster : public SkSpecialImage_Base {
    212 public:
    213     SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps* props)
    214         : INHERITED(subset, bm.getGenerationID(), props)
    215         , fBitmap(bm)
    216     {
    217         SkASSERT(bm.pixelRef());
    218         SkASSERT(fBitmap.getPixels());
    219     }
    220 
    221     SkAlphaType alphaType() const override { return fBitmap.alphaType(); }
    222 
    223     size_t getSize() const override { return fBitmap.computeByteSize(); }
    224 
    225     void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
    226         SkRect dst = SkRect::MakeXYWH(x, y,
    227                                       this->subset().width(), this->subset().height());
    228 
    229         canvas->drawBitmapRect(fBitmap, this->subset(),
    230                                dst, paint, SkCanvas::kStrict_SrcRectConstraint);
    231     }
    232 
    233     bool onGetROPixels(SkBitmap* bm) const override {
    234         *bm = fBitmap;
    235         return true;
    236     }
    237 
    238     SkColorSpace* onGetColorSpace() const override {
    239         return fBitmap.colorSpace();
    240     }
    241 
    242 #if SK_SUPPORT_GPU
    243     sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext* context) const override {
    244         if (context) {
    245             return GrMakeCachedBitmapProxy(context->contextPriv().proxyProvider(), fBitmap);
    246         }
    247 
    248         return nullptr;
    249     }
    250 #endif
    251 
    252 // TODO: The raster implementations of image filters all currently assume that the pixels are
    253 // legacy N32. Until they actually check the format and operate on sRGB or F16 data appropriately,
    254 // we can't enable this. (They will continue to produce incorrect results, but less-so).
    255 #define RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16 0
    256 
    257     sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
    258                                           const SkISize& size, SkAlphaType at) const override {
    259 #if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
    260         SkColorSpace* colorSpace = outProps.colorSpace();
    261 #else
    262         SkColorSpace* colorSpace = nullptr;
    263 #endif
    264         SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
    265             ? kRGBA_F16_SkColorType : kN32_SkColorType;
    266         SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
    267                                              sk_ref_sp(colorSpace));
    268         return SkSpecialSurface::MakeRaster(info, nullptr);
    269     }
    270 
    271     sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
    272         SkBitmap subsetBM;
    273 
    274         if (!fBitmap.extractSubset(&subsetBM, subset)) {
    275             return nullptr;
    276         }
    277 
    278         return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(subset.width(), subset.height()),
    279                                               subsetBM,
    280                                               &this->props());
    281     }
    282 
    283     sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
    284         if (subset) {
    285             SkBitmap subsetBM;
    286 
    287             if (!fBitmap.extractSubset(&subsetBM, *subset)) {
    288                 return nullptr;
    289             }
    290 
    291             return SkImage::MakeFromBitmap(subsetBM);
    292         }
    293 
    294         return SkImage::MakeFromBitmap(fBitmap);
    295     }
    296 
    297     sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
    298                                         const SkISize& size, SkAlphaType at) const override {
    299 #if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16
    300         SkColorSpace* colorSpace = outProps.colorSpace();
    301 #else
    302         SkColorSpace* colorSpace = nullptr;
    303 #endif
    304         SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
    305             ? kRGBA_F16_SkColorType : kN32_SkColorType;
    306         SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
    307                                              sk_ref_sp(colorSpace));
    308         return SkSurface::MakeRaster(info);
    309     }
    310 
    311 private:
    312     SkBitmap fBitmap;
    313 
    314     typedef SkSpecialImage_Base INHERITED;
    315 };
    316 
    317 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset,
    318                                                      const SkBitmap& bm,
    319                                                      const SkSurfaceProps* props) {
    320     SkASSERT(rect_fits(subset, bm.width(), bm.height()));
    321 
    322     if (!bm.pixelRef()) {
    323         return nullptr;
    324     }
    325 
    326     const SkBitmap* srcBM = &bm;
    327     SkBitmap tmp;
    328     // ImageFilters only handle N32 at the moment, so force our src to be that
    329     if (!valid_for_imagefilters(bm.info())) {
    330         if (!tmp.tryAllocPixels(bm.info().makeColorType(kN32_SkColorType)) ||
    331             !bm.readPixels(tmp.info(), tmp.getPixels(), tmp.rowBytes(), 0, 0))
    332         {
    333             return nullptr;
    334         }
    335         srcBM = &tmp;
    336     }
    337     return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props);
    338 }
    339 
    340 #if SK_SUPPORT_GPU
    341 ///////////////////////////////////////////////////////////////////////////////
    342 static sk_sp<SkImage> wrap_proxy_in_image(GrContext* context, sk_sp<GrTextureProxy> proxy,
    343                                           SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
    344     return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, alphaType,
    345                                    std::move(proxy), std::move(colorSpace), SkBudgeted::kYes);
    346 }
    347 
    348 class SkSpecialImage_Gpu : public SkSpecialImage_Base {
    349 public:
    350     SkSpecialImage_Gpu(GrContext* context, const SkIRect& subset,
    351                        uint32_t uniqueID, sk_sp<GrTextureProxy> proxy, SkAlphaType at,
    352                        sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props)
    353         : INHERITED(subset, uniqueID, props)
    354         , fContext(context)
    355         , fTextureProxy(std::move(proxy))
    356         , fAlphaType(at)
    357         , fColorSpace(std::move(colorSpace))
    358         , fAddedRasterVersionToCache(false) {
    359     }
    360 
    361     ~SkSpecialImage_Gpu() override {
    362         if (fAddedRasterVersionToCache.load()) {
    363             SkNotifyBitmapGenIDIsStale(this->uniqueID());
    364         }
    365     }
    366 
    367     SkAlphaType alphaType() const override { return fAlphaType; }
    368 
    369     size_t getSize() const override { return fTextureProxy->gpuMemorySize(); }
    370 
    371     void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override {
    372         SkRect dst = SkRect::MakeXYWH(x, y,
    373                                       this->subset().width(), this->subset().height());
    374 
    375         // TODO: In this instance we know we're going to draw a sub-portion of the backing
    376         // texture into the canvas so it is okay to wrap it in an SkImage. This poses
    377         // some problems for full deferral however in that when the deferred SkImage_Gpu
    378         // instantiates itself it is going to have to either be okay with having a larger
    379         // than expected backing texture (unlikely) or the 'fit' of the SurfaceProxy needs
    380         // to be tightened (if it is deferred).
    381         sk_sp<SkImage> img = sk_sp<SkImage>(new SkImage_Gpu(canvas->getGrContext(),
    382                                                             this->uniqueID(), fAlphaType,
    383                                                             fTextureProxy,
    384                                                             fColorSpace, SkBudgeted::kNo));
    385 
    386         canvas->drawImageRect(img, this->subset(),
    387                               dst, paint, SkCanvas::kStrict_SrcRectConstraint);
    388     }
    389 
    390     GrContext* onGetContext() const override { return fContext; }
    391 
    392     sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext*) const override {
    393         return fTextureProxy;
    394     }
    395 
    396     bool onGetROPixels(SkBitmap* dst) const override {
    397         const auto desc = SkBitmapCacheDesc::Make(this->uniqueID(), this->width(), this->height());
    398         if (SkBitmapCache::Find(desc, dst)) {
    399             SkASSERT(dst->getGenerationID() == this->uniqueID());
    400             SkASSERT(dst->isImmutable());
    401             SkASSERT(dst->getPixels());
    402             return true;
    403         }
    404 
    405         SkPixmap pmap;
    406         SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(),
    407                                                 this->alphaType(), fColorSpace);
    408         auto rec = SkBitmapCache::Alloc(desc, info, &pmap);
    409         if (!rec) {
    410             return false;
    411         }
    412         sk_sp<SkColorSpace> colorSpace;
    413         if (GrPixelConfigIsSRGB(fTextureProxy->config())) {
    414             colorSpace = SkColorSpace::MakeSRGB();
    415         }
    416         sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
    417                 fTextureProxy, std::move(colorSpace));
    418         if (!sContext) {
    419             return false;
    420         }
    421 
    422         if (!sContext->readPixels(info, pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
    423             return false;
    424         }
    425 
    426         SkBitmapCache::Add(std::move(rec), dst);
    427         fAddedRasterVersionToCache.store(true);
    428         return true;
    429     }
    430 
    431     SkColorSpace* onGetColorSpace() const override {
    432         return fColorSpace.get();
    433     }
    434 
    435     sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps,
    436                                           const SkISize& size, SkAlphaType at) const override {
    437         if (!fContext) {
    438             return nullptr;
    439         }
    440 
    441         SkColorSpace* colorSpace = outProps.colorSpace();
    442         return SkSpecialSurface::MakeRenderTarget(
    443             fContext, size.width(), size.height(),
    444             GrRenderableConfigForColorSpace(colorSpace), sk_ref_sp(colorSpace));
    445     }
    446 
    447     sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override {
    448         return SkSpecialImage::MakeDeferredFromGpu(fContext,
    449                                                    subset,
    450                                                    this->uniqueID(),
    451                                                    fTextureProxy,
    452                                                    fColorSpace,
    453                                                    &this->props(),
    454                                                    fAlphaType);
    455     }
    456 
    457     // TODO: move all the logic here into the subset-flavor GrSurfaceProxy::copy?
    458     sk_sp<SkImage> onAsImage(const SkIRect* subset) const override {
    459         if (subset) {
    460             // TODO: if this becomes a bottle neck we could base this logic on what the size
    461             // will be when it is finally instantiated - but that is more fraught.
    462             if (GrProxyProvider::IsFunctionallyExact(fTextureProxy.get()) &&
    463                 0 == subset->fLeft && 0 == subset->fTop &&
    464                 fTextureProxy->width() == subset->width() &&
    465                 fTextureProxy->height() == subset->height()) {
    466                 // The existing GrTexture is already tight so reuse it in the SkImage
    467                 return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace);
    468             }
    469 
    470             sk_sp<GrTextureProxy> subsetProxy(GrSurfaceProxy::Copy(fContext, fTextureProxy.get(),
    471                                                                    GrMipMapped::kNo, *subset,
    472                                                                    SkBudgeted::kYes));
    473             if (!subsetProxy) {
    474                 return nullptr;
    475             }
    476 
    477             SkASSERT(subsetProxy->priv().isExact());
    478             // MDB: this is acceptable (wrapping subsetProxy in an SkImage) bc Copy will
    479             // return a kExact-backed proxy
    480             return wrap_proxy_in_image(fContext, std::move(subsetProxy), fAlphaType, fColorSpace);
    481         }
    482 
    483         fTextureProxy->priv().exactify();
    484 
    485         return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace);
    486     }
    487 
    488     sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps,
    489                                         const SkISize& size, SkAlphaType at) const override {
    490         SkColorSpace* colorSpace = outProps.colorSpace();
    491         SkColorType colorType = colorSpace && colorSpace->gammaIsLinear()
    492             ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType;
    493         SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at,
    494                                              sk_ref_sp(colorSpace));
    495         return SkSurface::MakeRenderTarget(fContext, SkBudgeted::kYes, info);
    496     }
    497 
    498 private:
    499     GrContext*              fContext;
    500     sk_sp<GrTextureProxy>   fTextureProxy;
    501     const SkAlphaType       fAlphaType;
    502     sk_sp<SkColorSpace>     fColorSpace;
    503     mutable SkAtomic<bool>  fAddedRasterVersionToCache;
    504 
    505     typedef SkSpecialImage_Base INHERITED;
    506 };
    507 
    508 sk_sp<SkSpecialImage> SkSpecialImage::MakeDeferredFromGpu(GrContext* context,
    509                                                           const SkIRect& subset,
    510                                                           uint32_t uniqueID,
    511                                                           sk_sp<GrTextureProxy> proxy,
    512                                                           sk_sp<SkColorSpace> colorSpace,
    513                                                           const SkSurfaceProps* props,
    514                                                           SkAlphaType at) {
    515     SkASSERT(rect_fits(subset, proxy->width(), proxy->height()));
    516     return sk_make_sp<SkSpecialImage_Gpu>(context, subset, uniqueID, std::move(proxy), at,
    517                                           std::move(colorSpace), props);
    518 }
    519 #endif
    520