SkGrPixelRef.cpp revision 9323b8b8e16df4adcd63ee8496a6382e8df535c9
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. 21SK_DECLARE_STATIC_MUTEX(gROLockPixelsPixelRefMutex); 22 23SkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info) 24 : INHERITED(info, &gROLockPixelsPixelRefMutex) {} 25 26SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {} 27 28bool 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 46void SkROLockPixelsPixelRef::onUnlockPixels() { 47 fBitmap.unlockPixels(); 48} 49 50bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const { 51 return false; 52} 53 54/////////////////////////////////////////////////////////////////////////////// 55 56static 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 SkIRect srcRect; 68 69 if (!subset) { 70 desc.fWidth = texture->width(); 71 desc.fHeight = texture->height(); 72 srcRect = SkIRect::MakeWH(texture->width(), texture->height()); 73 } else { 74 SkASSERT(SkIRect::MakeWH(texture->width(), texture->height()).contains(*subset)); 75 // Create a new texture that is the size of subset. 76 desc.fWidth = subset->width(); 77 desc.fHeight = subset->height(); 78 srcRect = *subset; 79 } 80 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; 81 desc.fConfig = SkImageInfo2GrPixelConfig(dstCT, kPremul_SkAlphaType); 82 83 GrTexture* dst = context->createUncachedTexture(desc, NULL, 0); 84 if (NULL == dst) { 85 return NULL; 86 } 87 88 // Blink is relying on the above copy being sent to GL immediately in the case when the source 89 // is a WebGL canvas backing store. We could have a TODO to remove this flush flag, but we have 90 // a larger TODO to remove SkGrPixelRef entirely. 91 context->copySurface(dst->asRenderTarget(), texture, srcRect, SkIPoint::Make(0,0), 92 GrContext::kFlushWrites_PixelOp); 93 94 SkImageInfo info = SkImageInfo::Make(desc.fWidth, desc.fHeight, dstCT, kPremul_SkAlphaType); 95 SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, dst)); 96 SkSafeUnref(dst); 97 return pixelRef; 98} 99 100/////////////////////////////////////////////////////////////////////////////// 101 102SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface, 103 bool transferCacheLock) : INHERITED(info) { 104 // For surfaces that are both textures and render targets, the texture owns the 105 // render target but not vice versa. So we ref the texture to keep both alive for 106 // the lifetime of this pixel ref. 107 fSurface = SkSafeRef(surface->asTexture()); 108 if (NULL == fSurface) { 109 fSurface = SkSafeRef(surface); 110 } 111 fUnlock = transferCacheLock; 112 113 if (fSurface) { 114 SkASSERT(info.width() <= fSurface->width()); 115 SkASSERT(info.height() <= fSurface->height()); 116 } 117} 118 119SkGrPixelRef::~SkGrPixelRef() { 120 if (fUnlock) { 121 GrContext* context = fSurface->getContext(); 122 GrTexture* texture = fSurface->asTexture(); 123 if (context && texture) { 124 context->unlockScratchTexture(texture); 125 } 126 } 127 SkSafeUnref(fSurface); 128} 129 130GrTexture* SkGrPixelRef::getTexture() { 131 if (fSurface) { 132 return fSurface->asTexture(); 133 } 134 return NULL; 135} 136 137SkPixelRef* SkGrPixelRef::deepCopy(SkColorType dstCT, const SkIRect* subset) { 138 if (NULL == fSurface) { 139 return NULL; 140 } 141 142 // Note that when copying a render-target-backed pixel ref, we 143 // return a texture-backed pixel ref instead. This is because 144 // render-target pixel refs are usually created in conjunction with 145 // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live 146 // independently of that texture. Texture-backed pixel refs, on the other 147 // hand, own their GrTextures, and are thus self-contained. 148 return copy_to_new_texture_pixelref(fSurface->asTexture(), dstCT, subset); 149} 150 151static bool tryAllocBitmapPixels(SkBitmap* bitmap) { 152 SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator(); 153 if (NULL != allocator) { 154 return allocator->allocPixelRef(bitmap, 0); 155 } else { 156 // DiscardableMemory is not available, fallback to default allocator 157 return bitmap->tryAllocPixels(); 158 } 159} 160 161bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { 162 if (NULL == fSurface || fSurface->wasDestroyed()) { 163 return false; 164 } 165 166 SkIRect bounds; 167 if (subset) { 168 bounds = *subset; 169 } else { 170 bounds = SkIRect::MakeWH(this->info().width(), this->info().height()); 171 } 172 173 //Check the cache 174 if(!SkBitmapCache::Find(this->getGenerationID(), bounds, dst)) { 175 //Cache miss 176 177 SkBitmap cachedBitmap; 178 cachedBitmap.setInfo(this->info().makeWH(bounds.width(), bounds.height())); 179 180 // If we can't alloc the pixels, then fail 181 if (!tryAllocBitmapPixels(&cachedBitmap)) { 182 return false; 183 } 184 185 // Try to read the pixels from the surface 186 void* buffer = cachedBitmap.getPixels(); 187 bool readPixelsOk = fSurface->readPixels(bounds.fLeft, bounds.fTop, 188 bounds.width(), bounds.height(), 189 kSkia8888_GrPixelConfig, 190 buffer, cachedBitmap.rowBytes()); 191 192 if (!readPixelsOk) { 193 return false; 194 } 195 196 // If we are here, pixels were read correctly from the surface. 197 cachedBitmap.setImmutable(); 198 //Add to the cache 199 SkBitmapCache::Add(this->getGenerationID(), bounds, cachedBitmap); 200 201 dst->swap(cachedBitmap); 202 } 203 204 return true; 205 206} 207