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