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