Home | History | Annotate | Download | only in image
      1 /*
      2  * Copyright 2012 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 "GrCaps.h"
      9 #include "GrContext.h"
     10 #include "GrDrawContext.h"
     11 #include "GrImageIDTextureAdjuster.h"
     12 #include "effects/GrYUVEffect.h"
     13 #include "SkCanvas.h"
     14 #include "SkBitmapCache.h"
     15 #include "SkGpuDevice.h"
     16 #include "SkGrPixelRef.h"
     17 #include "SkGrPriv.h"
     18 #include "SkImageFilter.h"
     19 #include "SkImage_Gpu.h"
     20 #include "SkPixelRef.h"
     21 
     22 SkImage_Gpu::SkImage_Gpu(int w, int h, uint32_t uniqueID, SkAlphaType at, GrTexture* tex,
     23                          SkBudgeted budgeted)
     24     : INHERITED(w, h, uniqueID)
     25     , fTexture(SkRef(tex))
     26     , fAlphaType(at)
     27     , fBudgeted(budgeted)
     28     , fAddedRasterVersionToCache(false)
     29 {
     30     SkASSERT(tex->width() == w);
     31     SkASSERT(tex->height() == h);
     32 }
     33 
     34 SkImage_Gpu::~SkImage_Gpu() {
     35     if (fAddedRasterVersionToCache.load()) {
     36         SkNotifyBitmapGenIDIsStale(this->uniqueID());
     37     }
     38 }
     39 
     40 extern void SkTextureImageApplyBudgetedDecision(SkImage* image) {
     41     if (as_IB(image)->getTexture()) {
     42         ((SkImage_Gpu*)image)->applyBudgetDecision();
     43     }
     44 }
     45 
     46 static SkImageInfo make_info(int w, int h, bool isOpaque) {
     47     return SkImageInfo::MakeN32(w, h, isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
     48 }
     49 
     50 bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const {
     51     if (SkBitmapCache::Find(this->uniqueID(), dst)) {
     52         SkASSERT(dst->getGenerationID() == this->uniqueID());
     53         SkASSERT(dst->isImmutable());
     54         SkASSERT(dst->getPixels());
     55         return true;
     56     }
     57 
     58     if (!dst->tryAllocPixels(make_info(this->width(), this->height(), this->isOpaque()))) {
     59         return false;
     60     }
     61     if (!fTexture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
     62                               dst->getPixels(), dst->rowBytes())) {
     63         return false;
     64     }
     65 
     66     dst->pixelRef()->setImmutableWithID(this->uniqueID());
     67     if (kAllow_CachingHint == chint) {
     68         SkBitmapCache::Add(this->uniqueID(), *dst);
     69         fAddedRasterVersionToCache.store(true);
     70     }
     71     return true;
     72 }
     73 
     74 bool SkImage_Gpu::asBitmapForImageFilters(SkBitmap* bitmap) const {
     75     bitmap->setInfo(make_info(this->width(), this->height(), this->isOpaque()));
     76     bitmap->setPixelRef(new SkGrPixelRef(bitmap->info(), fTexture))->unref();
     77     bitmap->pixelRef()->setImmutableWithID(this->uniqueID());
     78     return true;
     79 }
     80 
     81 GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrTextureParams& params) const {
     82     return GrImageTextureAdjuster(as_IB(this)).refTextureSafeForParams(params, nullptr);
     83 }
     84 
     85 bool SkImage_Gpu::isOpaque() const {
     86     return GrPixelConfigIsOpaque(fTexture->config()) || fAlphaType == kOpaque_SkAlphaType;
     87 }
     88 
     89 static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
     90     switch (info.colorType()) {
     91         case kRGBA_8888_SkColorType:
     92         case kBGRA_8888_SkColorType:
     93             break;
     94         default:
     95             return; // nothing to do
     96     }
     97 
     98     // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
     99     // and in either case, the alpha-byte is always in the same place, so we can safely call
    100     // SkPreMultiplyColor()
    101     //
    102     SkColor* row = (SkColor*)pixels;
    103     for (int y = 0; y < info.height(); ++y) {
    104         for (int x = 0; x < info.width(); ++x) {
    105             row[x] = SkPreMultiplyColor(row[x]);
    106         }
    107     }
    108 }
    109 
    110 bool SkImage_Gpu::onReadPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
    111                                int srcX, int srcY, CachingHint) const {
    112     GrPixelConfig config = SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType(),
    113                                                      info.profileType());
    114     uint32_t flags = 0;
    115     if (kUnpremul_SkAlphaType == info.alphaType() && kPremul_SkAlphaType == fAlphaType) {
    116         // let the GPU perform this transformation for us
    117         flags = GrContext::kUnpremul_PixelOpsFlag;
    118     }
    119     if (!fTexture->readPixels(srcX, srcY, info.width(), info.height(), config,
    120                               pixels, rowBytes, flags)) {
    121         return false;
    122     }
    123     // do we have to manually fix-up the alpha channel?
    124     //      src         dst
    125     //      unpremul    premul      fix manually
    126     //      premul      unpremul    done by kUnpremul_PixelOpsFlag
    127     // all other combos need to change.
    128     //
    129     // Should this be handled by Ganesh? todo:?
    130     //
    131     if (kPremul_SkAlphaType == info.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
    132         apply_premul(info, pixels, rowBytes);
    133     }
    134     return true;
    135 }
    136 
    137 SkImage* SkImage_Gpu::onNewSubset(const SkIRect& subset) const {
    138     GrContext* ctx = fTexture->getContext();
    139     GrSurfaceDesc desc = fTexture->desc();
    140     desc.fWidth = subset.width();
    141     desc.fHeight = subset.height();
    142 
    143     GrTexture* subTx = ctx->textureProvider()->createTexture(desc, fBudgeted);
    144     if (!subTx) {
    145         return nullptr;
    146     }
    147     ctx->copySurface(subTx, fTexture, subset, SkIPoint::Make(0, 0));
    148     return new SkImage_Gpu(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID, fAlphaType, subTx,
    149                            fBudgeted);
    150 }
    151 
    152 ///////////////////////////////////////////////////////////////////////////////////////////////////
    153 
    154 static SkImage* new_wrapped_texture_common(GrContext* ctx, const GrBackendTextureDesc& desc,
    155                                            SkAlphaType at, GrWrapOwnership ownership,
    156                                            SkImage::TextureReleaseProc releaseProc,
    157                                            SkImage::ReleaseContext releaseCtx) {
    158     if (desc.fWidth <= 0 || desc.fHeight <= 0) {
    159         return nullptr;
    160     }
    161     SkAutoTUnref<GrTexture> tex(ctx->textureProvider()->wrapBackendTexture(desc, ownership));
    162     if (!tex) {
    163         return nullptr;
    164     }
    165     if (releaseProc) {
    166         tex->setRelease(releaseProc, releaseCtx);
    167     }
    168 
    169     const SkBudgeted budgeted = SkBudgeted::kNo;
    170     return new SkImage_Gpu(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID, at, tex, budgeted);
    171 }
    172 
    173 SkImage* SkImage::NewFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc, SkAlphaType at,
    174                                  TextureReleaseProc releaseP, ReleaseContext releaseC) {
    175     return new_wrapped_texture_common(ctx, desc, at, kBorrow_GrWrapOwnership, releaseP, releaseC);
    176 }
    177 
    178 SkImage* SkImage::NewFromAdoptedTexture(GrContext* ctx, const GrBackendTextureDesc& desc,
    179                                         SkAlphaType at) {
    180     return new_wrapped_texture_common(ctx, desc, at, kAdopt_GrWrapOwnership, nullptr, nullptr);
    181 }
    182 
    183 SkImage* SkImage::NewFromTextureCopy(GrContext* ctx, const GrBackendTextureDesc& desc,
    184                                      SkAlphaType at) {
    185     if (desc.fWidth <= 0 || desc.fHeight <= 0) {
    186         return nullptr;
    187     }
    188 
    189     SkAutoTUnref<GrTexture> src(ctx->textureProvider()->wrapBackendTexture(
    190         desc, kBorrow_GrWrapOwnership));
    191     if (!src) {
    192         return nullptr;
    193     }
    194 
    195     SkAutoTUnref<GrTexture> dst(GrDeepCopyTexture(src, SkBudgeted::kYes));
    196     if (!dst) {
    197         return nullptr;
    198     }
    199 
    200     return new SkImage_Gpu(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID, at, dst,
    201                            SkBudgeted::kYes);
    202 }
    203 
    204 SkImage* SkImage::NewFromYUVTexturesCopy(GrContext* ctx , SkYUVColorSpace colorSpace,
    205                                          const GrBackendObject yuvTextureHandles[3],
    206                                          const SkISize yuvSizes[3],
    207                                          GrSurfaceOrigin origin) {
    208     const SkBudgeted budgeted = SkBudgeted::kYes;
    209 
    210     if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 ||
    211         yuvSizes[1].fWidth <= 0 || yuvSizes[1].fHeight <= 0 ||
    212         yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0) {
    213         return nullptr;
    214     }
    215     static const GrPixelConfig kConfig = kAlpha_8_GrPixelConfig;
    216     GrBackendTextureDesc yDesc;
    217     yDesc.fConfig = kConfig;
    218     yDesc.fOrigin = origin;
    219     yDesc.fSampleCnt = 0;
    220     yDesc.fTextureHandle = yuvTextureHandles[0];
    221     yDesc.fWidth = yuvSizes[0].fWidth;
    222     yDesc.fHeight = yuvSizes[0].fHeight;
    223 
    224     GrBackendTextureDesc uDesc;
    225     uDesc.fConfig = kConfig;
    226     uDesc.fOrigin = origin;
    227     uDesc.fSampleCnt = 0;
    228     uDesc.fTextureHandle = yuvTextureHandles[1];
    229     uDesc.fWidth = yuvSizes[1].fWidth;
    230     uDesc.fHeight = yuvSizes[1].fHeight;
    231 
    232     GrBackendTextureDesc vDesc;
    233     vDesc.fConfig = kConfig;
    234     vDesc.fOrigin = origin;
    235     vDesc.fSampleCnt = 0;
    236     vDesc.fTextureHandle = yuvTextureHandles[2];
    237     vDesc.fWidth = yuvSizes[2].fWidth;
    238     vDesc.fHeight = yuvSizes[2].fHeight;
    239 
    240     SkAutoTUnref<GrTexture> yTex(ctx->textureProvider()->wrapBackendTexture(
    241         yDesc, kBorrow_GrWrapOwnership));
    242     SkAutoTUnref<GrTexture> uTex(ctx->textureProvider()->wrapBackendTexture(
    243         uDesc, kBorrow_GrWrapOwnership));
    244     SkAutoTUnref<GrTexture> vTex(ctx->textureProvider()->wrapBackendTexture(
    245         vDesc, kBorrow_GrWrapOwnership));
    246     if (!yTex || !uTex || !vTex) {
    247         return nullptr;
    248     }
    249 
    250     GrSurfaceDesc dstDesc;
    251     // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
    252     dstDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    253     dstDesc.fOrigin = origin;
    254     dstDesc.fWidth = yuvSizes[0].fWidth;
    255     dstDesc.fHeight = yuvSizes[0].fHeight;
    256     dstDesc.fConfig = kRGBA_8888_GrPixelConfig;
    257     dstDesc.fSampleCnt = 0;
    258 
    259     SkAutoTUnref<GrTexture> dst(ctx->textureProvider()->createTexture(dstDesc, SkBudgeted::kYes));
    260     if (!dst) {
    261         return nullptr;
    262     }
    263 
    264     GrPaint paint;
    265     paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
    266     paint.addColorFragmentProcessor(GrYUVEffect::CreateYUVToRGB(yTex, uTex, vTex, yuvSizes,
    267                                                                 colorSpace))->unref();
    268 
    269     const SkRect rect = SkRect::MakeWH(SkIntToScalar(dstDesc.fWidth),
    270                                        SkIntToScalar(dstDesc.fHeight));
    271     SkAutoTUnref<GrDrawContext> drawContext(ctx->drawContext(dst->asRenderTarget()));
    272     if (!drawContext) {
    273         return nullptr;
    274     }
    275 
    276     drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect);
    277     ctx->flushSurfaceWrites(dst);
    278     return new SkImage_Gpu(dstDesc.fWidth, dstDesc.fHeight, kNeedNewImageUniqueID,
    279                            kOpaque_SkAlphaType, dst, budgeted);
    280 }
    281 
    282 static SkImage* create_image_from_maker(GrTextureMaker* maker, SkAlphaType at, uint32_t id) {
    283     SkAutoTUnref<GrTexture> texture(maker->refTextureForParams(GrTextureParams::ClampNoFilter()));
    284     if (!texture) {
    285         return nullptr;
    286     }
    287     return new SkImage_Gpu(texture->width(), texture->height(), id, at, texture,
    288                            SkBudgeted::kNo);
    289 }
    290 
    291 SkImage* SkImage::newTextureImage(GrContext *context) const {
    292     if (!context) {
    293         return nullptr;
    294     }
    295     if (GrTexture* peek = as_IB(this)->peekTexture()) {
    296         return peek->getContext() == context ? SkRef(const_cast<SkImage*>(this)) : nullptr;
    297     }
    298     // No way to check whether a image is premul or not?
    299     SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
    300 
    301     if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
    302         GrImageTextureMaker maker(context, cacher, this, kDisallow_CachingHint);
    303         return create_image_from_maker(&maker, at, this->uniqueID());
    304     }
    305     SkBitmap bmp;
    306     if (!this->asLegacyBitmap(&bmp, kRO_LegacyBitmapMode)) {
    307         return nullptr;
    308     }
    309     GrBitmapTextureMaker maker(context, bmp);
    310     return create_image_from_maker(&maker, at, this->uniqueID());
    311 }
    312 
    313 ///////////////////////////////////////////////////////////////////////////////////////////////////
    314 
    315 GrTexture* GrDeepCopyTexture(GrTexture* src, SkBudgeted budgeted) {
    316     GrContext* ctx = src->getContext();
    317 
    318     GrSurfaceDesc desc = src->desc();
    319     GrTexture* dst = ctx->textureProvider()->createTexture(desc, budgeted, nullptr, 0);
    320     if (!dst) {
    321         return nullptr;
    322     }
    323 
    324     const SkIRect srcR = SkIRect::MakeWH(desc.fWidth, desc.fHeight);
    325     const SkIPoint dstP = SkIPoint::Make(0, 0);
    326     ctx->copySurface(dst, src, srcR, dstP);
    327     ctx->flushSurfaceWrites(dst);
    328     return dst;
    329 }
    330 
    331