Home | History | Annotate | Download | only in gpu
      1 
      2 /*
      3  * Copyright 2010 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 
     11 #include "SkGrPixelRef.h"
     12 
     13 #include "GrContext.h"
     14 #include "GrTexture.h"
     15 #include "SkBitmapCache.h"
     16 #include "SkGr.h"
     17 #include "SkRect.h"
     18 
     19 // since we call lockPixels recursively on fBitmap, we need a distinct mutex,
     20 // to avoid deadlock with the default one provided by SkPixelRef.
     21 SK_DECLARE_STATIC_MUTEX(gROLockPixelsPixelRefMutex);
     22 
     23 SkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info)
     24     : INHERITED(info, &gROLockPixelsPixelRefMutex) {}
     25 
     26 SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {}
     27 
     28 bool SkROLockPixelsPixelRef::onNewLockPixels(LockRec* rec) {
     29     fBitmap.reset();
     30 //    SkDebugf("---------- calling readpixels in support of lockpixels\n");
     31     if (!this->onReadPixels(&fBitmap, NULL)) {
     32         SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n");
     33         return false;
     34     }
     35     fBitmap.lockPixels();
     36     if (NULL == fBitmap.getPixels()) {
     37         return false;
     38     }
     39 
     40     rec->fPixels = fBitmap.getPixels();
     41     rec->fColorTable = NULL;
     42     rec->fRowBytes = fBitmap.rowBytes();
     43     return true;
     44 }
     45 
     46 void SkROLockPixelsPixelRef::onUnlockPixels() {
     47     fBitmap.unlockPixels();
     48 }
     49 
     50 bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const {
     51     return false;
     52 }
     53 
     54 ///////////////////////////////////////////////////////////////////////////////
     55 
     56 static SkGrPixelRef* copy_to_new_texture_pixelref(GrTexture* texture, SkColorType dstCT,
     57                                            const SkIRect* subset) {
     58     if (NULL == texture || kUnknown_SkColorType == dstCT) {
     59         return NULL;
     60     }
     61     GrContext* context = texture->getContext();
     62     if (NULL == context) {
     63         return NULL;
     64     }
     65     GrTextureDesc desc;
     66 
     67     SkIPoint pointStorage;
     68     SkIPoint* topLeft;
     69     if (subset != NULL) {
     70         SkASSERT(SkIRect::MakeWH(texture->width(), texture->height()).contains(*subset));
     71         // Create a new texture that is the size of subset.
     72         desc.fWidth = subset->width();
     73         desc.fHeight = subset->height();
     74         pointStorage.set(subset->x(), subset->y());
     75         topLeft = &pointStorage;
     76     } else {
     77         desc.fWidth  = texture->width();
     78         desc.fHeight = texture->height();
     79         topLeft = NULL;
     80     }
     81     desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
     82     desc.fConfig = SkImageInfo2GrPixelConfig(dstCT, kPremul_SkAlphaType);
     83 
     84     GrTexture* dst = context->createUncachedTexture(desc, NULL, 0);
     85     if (NULL == dst) {
     86         return NULL;
     87     }
     88 
     89     context->copyTexture(texture, dst->asRenderTarget(), topLeft);
     90 
     91     // Blink is relying on the above copy being sent to GL immediately in the case when the source
     92     // is a WebGL canvas backing store. We could have a TODO to remove this flush, but we have a
     93     // larger TODO to remove SkGrPixelRef entirely.
     94     context->flush();
     95 
     96     SkImageInfo info = SkImageInfo::Make(desc.fWidth, desc.fHeight, dstCT, kPremul_SkAlphaType);
     97     SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, dst));
     98     SkSafeUnref(dst);
     99     return pixelRef;
    100 }
    101 
    102 ///////////////////////////////////////////////////////////////////////////////
    103 
    104 SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface,
    105                            bool transferCacheLock) : INHERITED(info) {
    106     // For surfaces that are both textures and render targets, the texture owns the
    107     // render target but not vice versa. So we ref the texture to keep both alive for
    108     // the lifetime of this pixel ref.
    109     fSurface = SkSafeRef(surface->asTexture());
    110     if (NULL == fSurface) {
    111         fSurface = SkSafeRef(surface);
    112     }
    113     fUnlock = transferCacheLock;
    114 
    115     if (fSurface) {
    116         SkASSERT(info.width() <= fSurface->width());
    117         SkASSERT(info.height() <= fSurface->height());
    118     }
    119 }
    120 
    121 SkGrPixelRef::~SkGrPixelRef() {
    122     if (fUnlock) {
    123         GrContext* context = fSurface->getContext();
    124         GrTexture* texture = fSurface->asTexture();
    125         if (context && texture) {
    126             context->unlockScratchTexture(texture);
    127         }
    128     }
    129     SkSafeUnref(fSurface);
    130 }
    131 
    132 GrTexture* SkGrPixelRef::getTexture() {
    133     if (fSurface) {
    134         return fSurface->asTexture();
    135     }
    136     return NULL;
    137 }
    138 
    139 SkPixelRef* SkGrPixelRef::deepCopy(SkColorType dstCT, const SkIRect* subset) {
    140     if (NULL == fSurface) {
    141         return NULL;
    142     }
    143 
    144     // Note that when copying a render-target-backed pixel ref, we
    145     // return a texture-backed pixel ref instead.  This is because
    146     // render-target pixel refs are usually created in conjunction with
    147     // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live
    148     // independently of that texture.  Texture-backed pixel refs, on the other
    149     // hand, own their GrTextures, and are thus self-contained.
    150     return copy_to_new_texture_pixelref(fSurface->asTexture(), dstCT, subset);
    151 }
    152 
    153 static bool tryAllocBitmapPixels(SkBitmap* bitmap) {
    154     SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator();
    155     if (NULL != allocator) {
    156         return allocator->allocPixelRef(bitmap, 0);
    157     } else {
    158         // DiscardableMemory is not available, fallback to default allocator
    159         return bitmap->tryAllocPixels();
    160     }
    161 }
    162 
    163 bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
    164     if (NULL == fSurface || fSurface->wasDestroyed()) {
    165         return false;
    166     }
    167 
    168     SkIRect bounds;
    169     if (subset) {
    170         bounds = *subset;
    171     } else {
    172         bounds = SkIRect::MakeWH(this->info().width(), this->info().height());
    173     }
    174 
    175     //Check the cache
    176     if(!SkBitmapCache::Find(this->getGenerationID(), bounds, dst)) {
    177         //Cache miss
    178 
    179         SkBitmap cachedBitmap;
    180         cachedBitmap.setInfo(this->info().makeWH(bounds.width(), bounds.height()));
    181 
    182         // If we can't alloc the pixels, then fail
    183         if (!tryAllocBitmapPixels(&cachedBitmap)) {
    184             return false;
    185         }
    186 
    187         // Try to read the pixels from the surface
    188         void* buffer = cachedBitmap.getPixels();
    189         bool readPixelsOk = fSurface->readPixels(bounds.fLeft, bounds.fTop,
    190                                 bounds.width(), bounds.height(),
    191                                 kSkia8888_GrPixelConfig,
    192                                 buffer, cachedBitmap.rowBytes());
    193 
    194         if (!readPixelsOk) {
    195             return false;
    196         }
    197 
    198         // If we are here, pixels were read correctly from the surface.
    199         cachedBitmap.setImmutable();
    200         //Add to the cache
    201         SkBitmapCache::Add(this->getGenerationID(), bounds, cachedBitmap);
    202 
    203         dst->swap(cachedBitmap);
    204     }
    205 
    206     return true;
    207 
    208 }
    209