SkGrPixelRef.cpp revision f2703d83da3ab2ae18b45231fd4f11e16cce3184
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 GrSurfaceDesc 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_GrSurfaceFlag | kNoStencil_GrSurfaceFlag; 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) : INHERITED(info) { 103 // For surfaces that are both textures and render targets, the texture owns the 104 // render target but not vice versa. So we ref the texture to keep both alive for 105 // the lifetime of this pixel ref. 106 fSurface = SkSafeRef(surface->asTexture()); 107 if (NULL == fSurface) { 108 fSurface = SkSafeRef(surface); 109 } 110 111 if (fSurface) { 112 SkASSERT(info.width() <= fSurface->width()); 113 SkASSERT(info.height() <= fSurface->height()); 114 } 115} 116 117SkGrPixelRef::~SkGrPixelRef() { 118 SkSafeUnref(fSurface); 119} 120 121GrTexture* SkGrPixelRef::getTexture() { 122 if (fSurface) { 123 return fSurface->asTexture(); 124 } 125 return NULL; 126} 127 128SkPixelRef* SkGrPixelRef::deepCopy(SkColorType dstCT, const SkIRect* subset) { 129 if (NULL == fSurface) { 130 return NULL; 131 } 132 133 // Note that when copying a render-target-backed pixel ref, we 134 // return a texture-backed pixel ref instead. This is because 135 // render-target pixel refs are usually created in conjunction with 136 // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live 137 // independently of that texture. Texture-backed pixel refs, on the other 138 // hand, own their GrTextures, and are thus self-contained. 139 return copy_to_new_texture_pixelref(fSurface->asTexture(), dstCT, subset); 140} 141 142static bool tryAllocBitmapPixels(SkBitmap* bitmap) { 143 SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator(); 144 if (NULL != allocator) { 145 return allocator->allocPixelRef(bitmap, 0); 146 } else { 147 // DiscardableMemory is not available, fallback to default allocator 148 return bitmap->tryAllocPixels(); 149 } 150} 151 152bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { 153 if (NULL == fSurface || fSurface->wasDestroyed()) { 154 return false; 155 } 156 157 SkIRect bounds; 158 if (subset) { 159 bounds = *subset; 160 } else { 161 bounds = SkIRect::MakeWH(this->info().width(), this->info().height()); 162 } 163 164 //Check the cache 165 if(!SkBitmapCache::Find(this->getGenerationID(), bounds, dst)) { 166 //Cache miss 167 168 SkBitmap cachedBitmap; 169 cachedBitmap.setInfo(this->info().makeWH(bounds.width(), bounds.height())); 170 171 // If we can't alloc the pixels, then fail 172 if (!tryAllocBitmapPixels(&cachedBitmap)) { 173 return false; 174 } 175 176 // Try to read the pixels from the surface 177 void* buffer = cachedBitmap.getPixels(); 178 bool readPixelsOk = fSurface->readPixels(bounds.fLeft, bounds.fTop, 179 bounds.width(), bounds.height(), 180 kSkia8888_GrPixelConfig, 181 buffer, cachedBitmap.rowBytes()); 182 183 if (!readPixelsOk) { 184 return false; 185 } 186 187 // If we are here, pixels were read correctly from the surface. 188 cachedBitmap.setImmutable(); 189 //Add to the cache 190 SkBitmapCache::Add(this->getGenerationID(), bounds, cachedBitmap); 191 192 dst->swap(cachedBitmap); 193 } 194 195 return true; 196 197} 198