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 #include "GrContext.h"
     13 #include "GrTexture.h"
     14 #include "SkGr.h"
     15 #include "SkRect.h"
     16 
     17 // since we call lockPixels recursively on fBitmap, we need a distinct mutex,
     18 // to avoid deadlock with the default one provided by SkPixelRef.
     19 SK_DECLARE_STATIC_MUTEX(gROLockPixelsPixelRefMutex);
     20 
     21 SkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info)
     22     : INHERITED(info, &gROLockPixelsPixelRefMutex) {}
     23 
     24 SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {}
     25 
     26 bool SkROLockPixelsPixelRef::onNewLockPixels(LockRec* rec) {
     27     fBitmap.reset();
     28 //    SkDebugf("---------- calling readpixels in support of lockpixels\n");
     29     if (!this->onReadPixels(&fBitmap, NULL)) {
     30         SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n");
     31         return false;
     32     }
     33     fBitmap.lockPixels();
     34     if (NULL == fBitmap.getPixels()) {
     35         return false;
     36     }
     37 
     38     rec->fPixels = fBitmap.getPixels();
     39     rec->fColorTable = NULL;
     40     rec->fRowBytes = fBitmap.rowBytes();
     41     return true;
     42 }
     43 
     44 void SkROLockPixelsPixelRef::onUnlockPixels() {
     45     fBitmap.unlockPixels();
     46 }
     47 
     48 bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const {
     49     return false;
     50 }
     51 
     52 ///////////////////////////////////////////////////////////////////////////////
     53 
     54 static SkGrPixelRef* copyToTexturePixelRef(GrTexture* texture, SkColorType dstCT,
     55                                            const SkIRect* subset) {
     56     if (NULL == texture || kUnknown_SkColorType == dstCT) {
     57         return NULL;
     58     }
     59     GrContext* context = texture->getContext();
     60     if (NULL == context) {
     61         return NULL;
     62     }
     63     GrTextureDesc desc;
     64 
     65     SkIPoint pointStorage;
     66     SkIPoint* topLeft;
     67     if (subset != NULL) {
     68         SkASSERT(SkIRect::MakeWH(texture->width(), texture->height()).contains(*subset));
     69         // Create a new texture that is the size of subset.
     70         desc.fWidth = subset->width();
     71         desc.fHeight = subset->height();
     72         pointStorage.set(subset->x(), subset->y());
     73         topLeft = &pointStorage;
     74     } else {
     75         desc.fWidth  = texture->width();
     76         desc.fHeight = texture->height();
     77         topLeft = NULL;
     78     }
     79     desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
     80     desc.fConfig = SkImageInfo2GrPixelConfig(dstCT, kPremul_SkAlphaType);
     81 
     82     GrTexture* dst = context->createUncachedTexture(desc, NULL, 0);
     83     if (NULL == dst) {
     84         return NULL;
     85     }
     86 
     87     context->copyTexture(texture, dst->asRenderTarget(), topLeft);
     88 
     89     // TODO: figure out if this is responsible for Chrome canvas errors
     90 #if 0
     91     // The render texture we have created (to perform the copy) isn't fully
     92     // functional (since it doesn't have a stencil buffer). Release it here
     93     // so the caller doesn't try to render to it.
     94     // TODO: we can undo this release when dynamic stencil buffer attach/
     95     // detach has been implemented
     96     dst->releaseRenderTarget();
     97 #endif
     98 
     99     SkImageInfo info = SkImageInfo::Make(desc.fWidth, desc.fHeight, dstCT, kPremul_SkAlphaType);
    100     SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, dst));
    101     SkSafeUnref(dst);
    102     return pixelRef;
    103 }
    104 
    105 ///////////////////////////////////////////////////////////////////////////////
    106 
    107 SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface,
    108                            bool transferCacheLock) : INHERITED(info) {
    109     // TODO: figure out if this is responsible for Chrome canvas errors
    110 #if 0
    111     // The GrTexture has a ref to the GrRenderTarget but not vice versa.
    112     // If the GrTexture exists take a ref to that (rather than the render
    113     // target)
    114     fSurface = surface->asTexture();
    115 #else
    116     fSurface = NULL;
    117 #endif
    118     if (NULL == fSurface) {
    119         fSurface = surface;
    120     }
    121     fUnlock = transferCacheLock;
    122     SkSafeRef(surface);
    123 
    124     if (fSurface) {
    125         SkASSERT(info.fWidth <= fSurface->width());
    126         SkASSERT(info.fHeight <= fSurface->height());
    127     }
    128 }
    129 
    130 SkGrPixelRef::~SkGrPixelRef() {
    131     if (fUnlock) {
    132         GrContext* context = fSurface->getContext();
    133         GrTexture* texture = fSurface->asTexture();
    134         if (NULL != context && NULL != texture) {
    135             context->unlockScratchTexture(texture);
    136         }
    137     }
    138     SkSafeUnref(fSurface);
    139 }
    140 
    141 GrTexture* SkGrPixelRef::getTexture() {
    142     if (NULL != fSurface) {
    143         return fSurface->asTexture();
    144     }
    145     return NULL;
    146 }
    147 
    148 SkPixelRef* SkGrPixelRef::deepCopy(SkColorType dstCT, const SkIRect* subset) {
    149     if (NULL == fSurface) {
    150         return NULL;
    151     }
    152 
    153     // Note that when copying a render-target-backed pixel ref, we
    154     // return a texture-backed pixel ref instead.  This is because
    155     // render-target pixel refs are usually created in conjunction with
    156     // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live
    157     // independently of that texture.  Texture-backed pixel refs, on the other
    158     // hand, own their GrTextures, and are thus self-contained.
    159     return copyToTexturePixelRef(fSurface->asTexture(), dstCT, subset);
    160 }
    161 
    162 bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
    163     if (NULL == fSurface || fSurface->wasDestroyed()) {
    164         return false;
    165     }
    166 
    167     int left, top, width, height;
    168     if (NULL != subset) {
    169         left = subset->fLeft;
    170         width = subset->width();
    171         top = subset->fTop;
    172         height = subset->height();
    173     } else {
    174         left = 0;
    175         width = this->info().fWidth;
    176         top = 0;
    177         height = this->info().fHeight;
    178     }
    179     if (!dst->allocPixels(SkImageInfo::MakeN32Premul(width, height))) {
    180         SkDebugf("SkGrPixelRef::onReadPixels failed to alloc bitmap for result!\n");
    181         return false;
    182     }
    183     SkAutoLockPixels al(*dst);
    184     void* buffer = dst->getPixels();
    185     return fSurface->readPixels(left, top, width, height,
    186                                 kSkia8888_GrPixelConfig,
    187                                 buffer, dst->rowBytes());
    188 }
    189