SkGrPixelRef.cpp revision 473f0aa2bb218e50fce5e19063f8c8fdaf57fad4
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. 19SK_DECLARE_STATIC_MUTEX(gROLockPixelsPixelRefMutex); 20 21SkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info) 22 : INHERITED(info, &gROLockPixelsPixelRefMutex) { 23} 24 25SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() { 26} 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* copyToTexturePixelRef(GrTexture* texture, SkBitmap::Config dstConfig, 57 const SkIRect* subset) { 58 if (NULL == texture) { 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 = SkBitmapConfig2GrPixelConfig(dstConfig); 83 84 SkImageInfo info; 85 if (!GrPixelConfig2ColorType(desc.fConfig, &info.fColorType)) { 86 return NULL; 87 } 88 info.fWidth = desc.fWidth; 89 info.fHeight = desc.fHeight; 90 info.fAlphaType = kPremul_SkAlphaType; 91 92 GrTexture* dst = context->createUncachedTexture(desc, NULL, 0); 93 if (NULL == dst) { 94 return NULL; 95 } 96 97 context->copyTexture(texture, dst->asRenderTarget(), topLeft); 98 99 // TODO: figure out if this is responsible for Chrome canvas errors 100#if 0 101 // The render texture we have created (to perform the copy) isn't fully 102 // functional (since it doesn't have a stencil buffer). Release it here 103 // so the caller doesn't try to render to it. 104 // TODO: we can undo this release when dynamic stencil buffer attach/ 105 // detach has been implemented 106 dst->releaseRenderTarget(); 107#endif 108 109 SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, dst)); 110 SkSafeUnref(dst); 111 return pixelRef; 112} 113 114/////////////////////////////////////////////////////////////////////////////// 115 116SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface, 117 bool transferCacheLock) 118 : INHERITED(info) 119{ 120 // TODO: figure out if this is responsible for Chrome canvas errors 121#if 0 122 // The GrTexture has a ref to the GrRenderTarget but not vice versa. 123 // If the GrTexture exists take a ref to that (rather than the render 124 // target) 125 fSurface = surface->asTexture(); 126#else 127 fSurface = NULL; 128#endif 129 if (NULL == fSurface) { 130 fSurface = surface; 131 } 132 fUnlock = transferCacheLock; 133 SkSafeRef(surface); 134} 135 136SkGrPixelRef::~SkGrPixelRef() { 137 if (fUnlock) { 138 GrContext* context = fSurface->getContext(); 139 GrTexture* texture = fSurface->asTexture(); 140 if (NULL != context && NULL != texture) { 141 context->unlockScratchTexture(texture); 142 } 143 } 144 SkSafeUnref(fSurface); 145} 146 147GrTexture* SkGrPixelRef::getTexture() { 148 if (NULL != fSurface) { 149 return fSurface->asTexture(); 150 } 151 return NULL; 152} 153 154SkPixelRef* SkGrPixelRef::deepCopy(SkBitmap::Config dstConfig, const SkIRect* subset) { 155 if (NULL == fSurface) { 156 return NULL; 157 } 158 159 // Note that when copying a render-target-backed pixel ref, we 160 // return a texture-backed pixel ref instead. This is because 161 // render-target pixel refs are usually created in conjunction with 162 // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live 163 // independently of that texture. Texture-backed pixel refs, on the other 164 // hand, own their GrTextures, and are thus self-contained. 165 return copyToTexturePixelRef(fSurface->asTexture(), dstConfig, subset); 166} 167 168bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { 169 if (NULL == fSurface || !fSurface->isValid()) { 170 return false; 171 } 172 173 int left, top, width, height; 174 if (NULL != subset) { 175 left = subset->fLeft; 176 width = subset->width(); 177 top = subset->fTop; 178 height = subset->height(); 179 } else { 180 left = 0; 181 width = fSurface->width(); 182 top = 0; 183 height = fSurface->height(); 184 } 185 dst->setConfig(SkBitmap::kARGB_8888_Config, width, height); 186 if (!dst->allocPixels()) { 187 SkDebugf("SkGrPixelRef::onReadPixels failed to alloc bitmap for result!\n"); 188 return false; 189 } 190 SkAutoLockPixels al(*dst); 191 void* buffer = dst->getPixels(); 192 return fSurface->readPixels(left, top, width, height, 193 kSkia8888_GrPixelConfig, 194 buffer, dst->rowBytes()); 195} 196